It seems like Go is reasonably well designed given its creators' goals, and many people like it, which is great. But I think you're being unfair to (some) critics. It's not that Go is missing "shiny new" features - Go is missing features that have been established for a very long time; generics and sum types have been around for decades and have been proven to work.
And to your last sentence, use in production is not a good measure of language quality (except in a tautological sense), because many non-technical factors strongly affect popularity.
Yeah, but the point of Go is to be minimal and easy. Basically, this makes it really hard to be clever. In both senses, unfortunately, but I see how it can be a net win for big projects.
I think that's perfectly fine, though it's not my cup of tea (and I doubt that empirical evidence would show that Go's particular set of features maximizes "big project" maintainability, though such an experiment is sadly impossible to arrange). And I think that the point, "Critics focus on missing features, but Go's philosophy is to be minimal" is definitely valid. But, "Critics focus on how Go is missing shiny new features (that may not even be fully implemented)" is definitely not true (of most critics). Most people aren't complaining that Go doesn't support dependent types, or row polymorphism, or cutting edge technologies. They're complaining that Go doesn't even reflect the state-of-the-art of 30 years ago.
They're complaining that Go doesn't even reflect the state-of-the-art of 30 years ago.
Clearly that was a very deliberate choice on the part of the Go creators, not the result of oversight or ignorance. I suspect they simply didn't want to reflect the state of the art 30 years ago, 20 years ago, or today. I don't find that at all surprising, because people who want to get things done often like very simple tools which stay out of the way. To each their own though, and I'm sure the go creators would be very happy to see other languages used instead of go by those who prefer more features, more complexity, state of the art from 30 years ago, etc. I do find myself puzzled by the hostility it generates though - it is just a language, one of many, and about which some very ordinary claims are being made (easy to learn etc).
There are a ton of anti features that have been introduced in the last 30 years. Things that are clever but make your code harder to understand and harder to maintain. Many of these are things people like, but have proven to be somewhere between not useful and a nightmare.
I'm not advocating adding every feature introduced in that span, only the ones that are not problematic. As a specific example, what's the downside to disjoint unions? They add minimal complexity while adding a ton of safety. I'm not aware of any argument that they are either not useful or a nightmare - could you point me to one?
So, by disjoint unions, I'm going to assume you mean sum types, like a value that can be either a pointer or an error, but never both, and you use special keywords to access one or the other.
Sure, that's really useful - you guarantee that you can never access the unset half of the value. But it adds a lot of complexity, too. You need a way to declare values of this type - this means more keywords and/or more special syntax. You need a way to then access both halves of the values, so now you have to add pattern matching... that's actually a lot of complexity to add to a language that only has 25 keywords.
All that, instead of just doing what Go already does, which is to return two values and just have a convention of checking the error before the value... which works really well 99% of the time, and doesn't require all the rest of that complexity.
The problem Go is trying to solve is that of programming at scale (say, a ten-million-line code base that will survive for two decades). The problem it is trying to solve is not how to make it easier to write very small parts of the program. These two are not the same problem. (Problems of scale are not the same problems but more of them. They are different problems.)
Does the functional style of maps and composition cause problems at scale? I don't have any data. However, I would not begin by assuming that Go's designers were either stupid or ignorant of functional programming idioms.
It sounds like you're trying to stuff too much in a single line. Line returns aren't in short supply. You can just write the loop and then write another loop. It'll be more clear that way anyway. And if you really do this a lot, write a nicely named helper function. That will also make your code more clear.
It's not clear; you suddenly have to read 5 times more code, your code no longer makes intent clear. You now have to understand the intent of multiple loops and make sure you're not introducing subtle bugs.
I cannot see a single way in which that is objectively "better".
More code does not mean less clear. I've seen some really hairy list comprehensions that I broke out into 3 loops and made them 1000x more clear, because you could actually follow what each conversion was doing.
You'll have to explain to me what you mean by composition if you don't mean foo(bar(baz())) or foo().bar().baz() Composition means putting things together, if you're not doing it on one line, then what's wrong with a loop?
For example, Iterators are composable. I can return one from a function, append another iterator to the chain, return that and then iterate over the whole result (possibly, this leads to only one iteration internally).
Type parameterization has been around for a long time, but all existing implementations make tradeoffs the Go team is not willing to make: http://research.swtch.com/generic
If there exists an implementation of type parameterization that imposes neither a compile time cost nor a run time cost, I would be interested in reading about it.
The languages and compilers I'm familiar with (Scala, Haskell, MLton) all pay a cost, usually in compile time.
The answer, as I understand, is that .NET has to copy code for each non-reference-type instantiation. .NET gets away with it because most types are reference typed and can use the same code.
In F#, you can use hat types via inlining to get even more power. Like creating a map function that works directly on List, Array, and Set - but without using any common interface. Pretty neat, but it emits the function's IL into every callsite so it can get out of hand.
I recall there being a mailing list thread on Go where the designers addressed this. I've no idea how Go is implemented so perhaps the multiple-copies problem is actually significant.
Technically, I believe that value types with the same layout could share implementations (though I don't believe this is implemented). In any case, if you don't have generics you have to do the same thing by hand anyway (e.g. create an IntList type, a DoubleList type, etc.), so I can't see how that's any better. More likely, I think, is that Go doesn't do JIT compilation, so there would be some challenges getting a comparable implementation built on Go's runtime. But .NET's new native toolchain solves the same problem, so it's clearly not insurmountable.
In cases static linking is used, which happens to be Go's case, this can be done at link time.
Also addressed by Ada generics for example. There are many others.
Strong typed languages with generics go back to CLU (1974), so there are lots of research material, as well as, real languages if one steps outside Java/C++ implementation mindset.
The Go designers clearly had full awareness of every language feature available in alternatives. They consciously and intentionally made the choices they did. This is obvious, of course, but often it is stated as if they came out of a cave, language in hand, unaware of all the great things they were missing.
And to your last sentence, use in production is not a good measure of language quality
It is actually a great indicator of the gap between abstract language tourism, and practical day to day development.
I will say again that Haskell is held as the perfect language and set of choices on here constantly (particularly when used to denigrate Go). Yet it is used for perilously few actual solutions (despite being around for decades).
Sometimes the things that seem incredibly important and of great value just aren't such a great value in the real world. Similarly, things that seem minor end up being very important.
Perhaps we're talking past each other - I'm certainly not saying Go should be Haskell (I've never even written a Haskell program!). Go's designers are clearly not stupid, and many people seem quite satisfied with their design choices. But that doesn't mean they "had full awareness of every language feature available in the alternatives", and even if they did, smart people are still susceptible to the blub paradox.
As for use in production, I agree that it can be a fair barometer for "utility", but I strongly disagree that it's a good measure of "quality" (as in, technical design choices). We live in a path-dependent world rife with network effects, so quality per se just doesn't matter all that much, and non-technical factors like "being backed by a major corporation" can matter a lot. I'm sure there's more Visual Basic in the wild than Go, but I'd hardly use that to argue that it's a superior language, or that Go proponents are "abstract language tourists".
>But that doesn't mean they "had full awareness of every language feature available in the alternatives", and even if they did, smart people are still susceptible to the blub paradox.
I think the blub paradox applies to everyone. Unless you spend time using a feature in earnest, it is easy to convince yourself that it's not valuable. Do you have reason to disagree?
no offense, man, yet this your statement is an example of the blub paradox.
"But when our hypothetical Blub programmer looks in the other direction, up the power continuum, he doesn't realize he's looking up. What he sees are merely weird languages. He probably considers them about equivalent in power to Blub ..."
it is like you looking up at Thompson and not realizing that you're looking up. You probably consider Thompson equivalent to you and everyone. (Again, no offense intended, though i can see how it can sound kind of offensive).
On the other hand, unless you spend a lot of time using a feature in earnest, it's hard to know that the feature is actually not necessary because it's an enormous workaround for something else.
> Suggesting application of Blub paradox to the people who invented Unix ...
Who mean the same people that disregarded memory safe system programming languages and decided to create their own "unsafe by default" one?
The same people that created a text based operating system, while at Xerox PARC GUI based workstations were being developed in memory safe system programming languages?
I was thinking about how much space they saved in their C strings by having a null byte instead of the Pascal style pointer and length struct ... on their original 16 bit systems, it was one. One byte! So much pain was caused by that decision.
more than 20 years ago i did write in PL/I some bits, and i did write in Algol on a system project (embedded OS and dev tools for it). Man, it is ugly.
it sounds a bit oxymoronic, at least on practice. I'm yet to see a normally functioning system written using "safe system programming language".
>The same people that created a text based operating system, while at Xerox PARC GUI based workstations were being developed in memory safe system programming languages?
i hope you don't mean Unix here because Unix has nothing to do with either "text based" or "GUI based" - it is completely orthogonal to that.
> But that doesn't mean they "had full awareness of every language feature available in the alternatives", and even if they did, smart people are still susceptible to the blub paradox.
I'm pretty sure Ken Thompson &co were fully aware of generics and sum types (to use your own example). It trades the implicit complication of implementing and using those (and other) features for strong concurrency. For a lot of people, that's a good tradeoff to make.
And to your last sentence, use in production is not a good measure of language quality (except in a tautological sense), because many non-technical factors strongly affect popularity.