And by that you mean "invent ad-hoc code generators instead of using built-in language features from the 21st century", right?
Yes, sometimes the simplicity of the language leaves you wanting a bit more power (typeclasses, macros) but the code quality seems (to me) better with the constrained language than with the unconstrained one.
Also, doing only GUIs is quite a bit more restrictive than general purpose programming and not every fancy feature may make sense there.
One example of code generators is enums, I'd love for Go to add that as a feature, I frequently use them in other languages. Go's equivalent is a list of consts with a shared prefix, e.g. StatusOK, StatusBadRequest etc for HTTP error codes [0], then functions to do anything with them (like getting a status text for the aforementioned HTTP status codes; see [0] and scroll down a bit).
I mean it's not difficult code; nobody has to learn any new syntax or methodologies to understand enums if they already know consts / variables, functions and switch/case statements. It's just inelegant and it feels unsafe - you need a linter [1] to check for exhaustiveness of the aforementioned switch/case, on top of a ton of other linters [2] that IMO should be language features or compiler checks.
My personal gripe is struct tags that are just strings that no tooling or compile-time checks will check, they're left up to a library (or the standard library) to interpret at runtime. In other languages like e.g. Java they introduced annotations to add metadata to properties.
[0] https://go.dev/src/net/http/status.go
edit: gp, not p
And partly because it needed more thought. I'm all for more well thought out features, but there's also value in a language that doesn't move fast and doesn't break things. And I say that while Python is my main work horse, so I understand what breaking things mean.
https://news.ycombinator.com/item?id=9622417
> We have spoken to a few true experts in Java generics and each of them has said roughly the same thing: be very careful, it's not as easy as it looks, and you're stuck with all the mistakes you make.
The Go team does their homework, and they do it thoroughly. I respect that more than anything about the language. Compare with Java, that had been stagnant in committees for nearly a decade, or with Javascript, that has been bolting on features left and right; I'm mainly thinking of the half-baked OOP addition.
To their credit, they don't just throw things into the language because it's trendy or "cool" at the moment. Even if people disagree with their decisions, they are well considered and thought about decisions.
Also, languages don’t start in a vacuum, they shouldn’t have to go through the whole process from zero each time — Go absolutely failed by not incorporating it from the first version.
Maybe this makes more sense:
Coming from more expressive languages, one of the good things I could say about Go's developer UX is that you are so helpless to circlejerk over abstractions that there is simply nothing else to do than to write concrete code to solve the problem.
Elm is similar versus the huge type expressive power of Haskell. Elm's type system is so minimal compared to similar languages that you can't spend hours perfecting your higher kinded advanced type abstraction that perfectly annotates and cordons off the problem domain because there isn't enough typing power to do that. You have to go "welp, good enough" and move on.