I had some of the same reactions as this fellow when I checked up on Google's new language Go. "So what", and then: "No one will ever seriously use this because of the lack of Exceptions". My general impression of Google these days is that of a lot of bright people running amok.. some good stuff, some mediocre stuff. But another language? really? Another half language?
http://golang.org/
I'm going to paste this whole review here because I found his pop-ups annoying, but you can follow the link for yourself:
http://monoc.mo.funpic.de/go-rant/
Oh but wait don't forget the other new language from Google:
http://code.google.com/p/noop/
In this case I find some of the concepts in this language resonate with me, and the language seems to be more of a project... Dependency Injection, (and even Aspect Weaving while we're at it) do need to be first class members of a language, and not add ons. (If you are in to that sort of thing) and (IMHO). Otherwise you end up with all sorts of edge case/side affect/configuration gotcha/just plain don't work issues that eat in to the overall gain in productivity you are supposed to get by using these concepts. The rest of NOOP I don't have a strong opinion on...
-------------------
Why Google's Go is a Bore
Summary
Here's my TL;DR summary of the following long rant: Google's Go programming language is a boring entry in the world of programming that got undeserved buzz only because of some names attached to it.
Preamble
There's been a lot of buzz lately around the new programming language from Google: Go. It gets this buzz primarily because of the names attached to the project, to wit:
- Google
- Ken Thompson
- Rob Pike
Rob Pike's name attracts attention because of his attachment to the undeservedly successful UNIX virus over thirty years ago. He's also one of the principles behind the UTF-8 encoding scheme. That's about it for major accomplishments. His name is otherwise attached to the much-admired but little-used Plan 9 and Inferno operating systems and the attendant language for the latter, Limbo. Ken Thompson is known for the C precursor language B plus his major contributions to the UNIX virus and to Plan 9.
Now, some of the deprecating language aside (I just think UNIX is vastly overrated as a modern OS), these two
are grandmasters of computing and deserve the many accolades and awards they've won. Still, without their names attached to the Go programming language there'd have been little to no notice paid to it for reasons I'll outline below.
And, of course, the addition of Google's name to the list doesn't hurt. There is a large amount of Google fanboi-ism out there that's driving much of the buzz around this new language.
Yet...
This language doesn't deserve the buzz. At all. It is for the most part devoid of innovation and, in fact, in a few places, falls short of what a normal modern language provides. Had this language been released without the three names attached to it the world's response to it would have been a huge collective yawn, and this is only if one presumes any notice would have been given at all. Putting this another way, were this language designed as part of an undergrad course in language design it would have earned a solid B.
Innovation
Now, not to take away from the genuine innovations that Go has in it, I'll put them front and centre:
- The channels-based approach to concurrency is interesting. CSP is a rich mine of concurrency implementation concepts and it's nice to see it explored more.
- The "goroutines" blend of coroutines and OS threads is an interesting way of doing things very similar to Erlang's BEAM virtual machine without having a virtual machine.
- The inheritance-free-yet-type-safe object system is a really cool idea that blends the many benefits of so-called duck typing while keeping solid compiler-enforced type checking in place.
It's because of these three innovations that Go deserves a B in a language design course, in fact. (It could have even earned a B+ were it not for the really ugly syntax, q.v. below for details.)
Innovation? We don't need no more stinkin' Innovation!
So, that's the innovation. These are innovations. Two of them are
very innovative. Too bad they're attached to a language that is otherwise a major step
backward in language design.
Exceptions
The first step backwards is the lack of exceptions. This is such a major step backwards that I'm wondering if Thompson and Pike have entered senility! Exceptions (or
some form of non-local transfer of control) are absolutely essential in any software project of any size. The reason has been known for decades: errors are usually, in any non-trivial software, detected where it is impossible to determine how to deal with it, while the levels of the software that know how to handle the error have no way to detect it. Something has to transmit that information from the place where the error is detected to the place where it can be handled. The old structured programming approach of returning explicit error codes fails on several grounds (not least of which is the problem of programmer laziness). The biggest two are:
- Returning error codes up the chain of function calls only works if programmers diligently check and return every error condition. (C programmers, be honest here: when was the last time you checked the return value of
printf()
?) If any function anywhere up the potentially dozens of chained function calls was written by a programmer who didn't bother to check errors, your whole program is screwed. The usual rejoinder at this point is "good programmers blah blah blah" but you don't put in language features assuming a good programmer. You put in language features assuming reality, and reality is that most programmers are mediocre.
- Even if, however, your programmers are all diligent and careful, there is another problem with returning errors manually: it obfuscates code badly. Each function call is surrounded by error handling which makes you lose the overall shape and structure of your code in the miasma of book-keeping code. The result is unbearably ugly to look at.
Generics
Another regressive problem is the lack of generics in the data types. You'd think that the designers of Go would have looked at the problems with Java when making their language. One of the worst design decisions made in Java was making all collections work through a process of down- and up-casting variable types in collections through the underlying "Object" type. This made code type-unsafe (kind of defeating the purpose of all those tediously repetitive type declarations) and has led to problems for years even now that Java has generics. (The generics are not well-implemented and still have type safety issues related to casting in edge conditions.) Hell, you could look back farther than Java for this. C++ was originally this way too and the latter-day workaround to this -- templates -- while typesafe are extremely complicated, ugly and much-derided outside of the C++ community as a result. If you design your language from the ground up to support generics, however, you avoid many of these problems. The Go designers chose not to do this. I predict that generics will be added later on and will either have major semantic issues (like Java) or really ugly syntax (like C++). Or possibly both.
"New Jersey" Design at its Best!
The aggravating part of all this is that the reasons given for these decisions come straight from the
New Jersey approach to design. According to the
the language design FAQ, the reason for not including these two features boils down to "we found it very hard to implement so we're passing the difficulty of the problem on to each and every programmer who chooses to use our language".
Why not just make them program in assembler? The whole
point of using a high level programming language is to have the language and its runtime handle the difficult, fiddly bits so that the programmer can focus on the problem domain instead of the minutiae of implementation. A language designer saying "I chose not to solve this difficult, but common, problem because it's too much work" is rather like a car designer saying "engines are hard to design, so we'll just make the passengers of the car push the vehicle". This attitude is especially aggravating when you're dealing with a topic which has been
solved in prior art! Generics have been part of language design for decades now! Don't like Java's generics? Or C++'s? That's fine. They both suck. Look at
other languages. Try Dylan. Or Eiffel. Or Modula-3. Or any of a hundred other languages that tackled this
and won. Don't cop out and whine about how hard it is!
Syntax
Still, with even these kinds of flaws, Go would get a solid B+. So why am I marking it down to B (and maybe even B- if I'm in a bad mood)?
The syntax.
Aside from it being Yet Another Squiggly Brace Language (q.v. B, C, C++, Java, C#, yadda yadda yadda for details) -- a continuation of the C blight, in short -- there is special ugliness in Go's core that makes me loathe it on sight. I'll just show a single example taken from the language's home page:
s := sum(&[...]int{1,2,3});
This was the first real "WTF?!" moment while I glanced over the language. I am no stranger to terse and cryptic languages. I'll pit Erlang and
Haskell against most languages for terseness and occasional ugliness. (Erlang records, I'm looking at you here!) There is, however, in my view, a difference between being terse and being ugly. Terse means the information is densely packed, but once you know the language it's easy to pick out the pieces. Ugly means the information may or may not be densely packed, but even if you know the language it's difficult to pick out the pieces. I've read and re-read the explanation for the supplied code a dozen times. When I read the explanation I can understand the code. If I leave it for an hour and go back, however, I cannot figure it out and need to read the explanation again. This is just bad design in my opinion. Erlang's records verge on this level of ugly, to be fair, but Erlang has one or two pieces of such ugly syntax. Go has many of them. I just showed you one example. Here are a few more:
var m map[string]int;
func CopyInBackground(dst, src chan Item) {
go func() { for { dst <- <-src } }()
}
if err := file.Chmod(0664); err != nil {
log.Stderr(err);
return err;
}
(Yes, that is a statement you see between "if" and the test. No, it serves no real purpose beyond obfuscation.)
More Disappointment
Other disappointments (but expected ones given the background of the people involved) in Go are:
- The lack of immutable variables. Especially given its focus on concurrency Go really should have gone that route with mutable variables being permitted, if at all, only with explicit flagging of them so the danger zones are known.
- Too, why this divide, again, with reference types and value types? Did they not learn from the problems this caused in Java? While Java slowly struggles its way free of that tarpit, the Go designers leap in headfirst. What gives? Oh, right. Check out the language design FAQ again and you'll see the New Jersey approach invoked.
- Why is the slice notation so underpowered? They stole the notation from Python, it seems, but decided that Python's slices were too powerful so they removed half the functionality. In Python it's easy, for example, to say "give me the slice that is everything except the first three and last three pieces of this array" because a negative offset means "start counting from the end". In Go you have to calculate the length of the array, attach an arithmetic expression to find the ending point of your slice and go from there.
- Have the language creators not learned their lessons from C? Why are "int", et al of "implementation-defined" size? This has been a known bad design for ages and interferes with cross-platform work in a big way. (This is why, for example, I use a 32-bit OS on a 64-bit processor. A lot of programs make assumptions about integer and pointer sizes that are just plain invalid. How can they do this? Pointer sizes and integer sizes are "implementation defined" in C and C++ programmers are too lazy to program properly in that space.) Yes I know that there are
int16
and uint64
and such types defined, but macros for doing this have been in place in C and C++ for ages and programmers STILL reach for the generic int
when writing programs where the integer size could be an issue. You don't design languages for the hypothetical diligent programmer. You design them for reality.
- Why is an array and a slice of an array a fundamentally different type? Arrays are value types, for example, and slices are reference types.
- Seriously? There's
goto
but no exceptions? Really?!
Well, I'm out of steam on this rant. Why the vituperative venom if Go is so uninspired and boring? It's the noise around it, really. It's yet another celebration of technical mediocrity that has caused computing to never really live up to its potential. This offends me at a profound level.
--Michael T. Richter, November, 2009