> I also think Go's benefit really is that it's simple and that you have very few tools that let you do anything other than focusing on solving your problem
I feel just the opposite: Go has very few tools, which forces you to often have to solve language games instead of focusing on your problem.
You want to remove an element from a list? Instead of writing that, you need to iterate through the list and check if the element at position i has the properties you want, and if it does, copy the list from i+1 (if it wasn't the last!) over the original list. This is NOT the problem you were trying to solve.
You want to store a map from some struct to another? Instead of writing that, you have to create a key struct that is comparable for equality from your original struct, which probably involves string concatenation and great care to avoid accidentally making unequal structs have equal keys; and then two maps, one from keys to the key struct and another from keys to the value struct, and of course client code also has to know about this explicitly.
You want to pass around some large structs, or iterate over slices of them? Well, you'd better start using pointers, and start being careful about what is a copy and what isn't, otherwise you'll pay a steep performance price, without any syntactic indication.
You want to work with sets of values? You'll have to store them as map keys, perhaps doing all of the black voodoo described above. And of course, you can't do a reunion of two sets, you have to iterate through the keys of the first map and the second map and add them to a third map.
All of these things are annoying when you are writing them, and even more of a problem when you are reading the code, as you have to understand the intent from the messy internals that Go forces you to expose.
I feel just the opposite: Go has very few tools, which forces you to often have to solve language games instead of focusing on your problem.
You want to remove an element from a list? Instead of writing that, you need to iterate through the list and check if the element at position i has the properties you want, and if it does, copy the list from i+1 (if it wasn't the last!) over the original list. This is NOT the problem you were trying to solve.
You want to store a map from some struct to another? Instead of writing that, you have to create a key struct that is comparable for equality from your original struct, which probably involves string concatenation and great care to avoid accidentally making unequal structs have equal keys; and then two maps, one from keys to the key struct and another from keys to the value struct, and of course client code also has to know about this explicitly.
You want to pass around some large structs, or iterate over slices of them? Well, you'd better start using pointers, and start being careful about what is a copy and what isn't, otherwise you'll pay a steep performance price, without any syntactic indication.
You want to work with sets of values? You'll have to store them as map keys, perhaps doing all of the black voodoo described above. And of course, you can't do a reunion of two sets, you have to iterate through the keys of the first map and the second map and add them to a third map.
All of these things are annoying when you are writing them, and even more of a problem when you are reading the code, as you have to understand the intent from the messy internals that Go forces you to expose.