My posts on Google’s Go (Part 1 and Part 2) definitely touched a nerve with a few folks. And I appreciate good dialog on ideas like this…
One pervasive question that I keep hearing is “Who is Go good for?” And I’m having a hard time finding a good answer. Even Go’s own FAQ page is uncharacteristically vague about it.
I’d say there are plenty of non-starters to keep Go out of the application programming space. After my arguments pointing out that it won’t replace Java anytime soon, folks are telling me that I wasn’t looking at the right demographic. These people suggest that Go is really for systems programmers. Systems programming has typically been the bastion of C and (more recently) C++ programmers for the past 2 decades. If you’re doing serious systems programming, you’re in one of those two camps, generally speaking. Maybe with a touch of assembly here and there.
OK, I’m game for looking at that. First off, what makes a good systems programming language? Here are few things we might want:
- can operate in resource-constrained environments
- is very efficient and has little runtime overhead
- has a small runtime library, or none at all
- allows for direct and “raw” control over memory access and control flow
- lets the programmer write parts of the program directly in assembly language
Does Go really fit into that box?
- Go’s performance numbers are rough 6x worse than C++, on average. The best performing Go test was comparable to the worst C test. While I gave Go some leniency with Java on performance in an application environment (there are plenty of other non-memory, non-CPU bottlenecks to worry about there), the systems world is far stricter about raw, unabashed execution time and resource consumption. (+10/20 pts)
- Go’s memory and execution footprint are higher than C and C++, according to these stats. Not exactly an ideal candidate for replacing either of these languages currently entrenched in this space. An interesting experiment: Compile Hello World in Go and C++. Go’s compiled & linked output: 38K, C++ clocks in at 6K, about 84% smaller. (+10/20 pts)
- If you include the garbage collector, the Go runtime footprint is certainly larger than C/C++. But it’s safer than either C/C++ for the same reason. And to top it off: Go’s garbage collector isn’t parallel safe right now. (To be fair, that’s the #1 thing on the TODO list right now for the Go team) (+15/20 pts)
- Raw and direct control is possible, so Go checks in fine here. You can use this to investigate runtime structures if you like. (+20/20 pts)
- This is similar to Java’s native interface (JNI), but statically linked. So yes, it’s possible. (+20/20 pts)
At 20 pts per question, let’s be kind and give Go a 75/100 possible score there (A solid “C” on the American grading scale, yuck yuck…). If you’re a C/C++ programmer where you’re already at 100/100 on the above chart, where is your motive to switch here? Couple that with the fact that systems programmers are not exactly known for adopting bleeding edge technology at a rapid pace. It was years before C++ ever made substantial inroads with the embedded C crowd. Considering the degree of reliability required to do high quality, bare-metal systems programming, I’d be skeptical of anything new in this space too.
Finally, let’s hit up the syntax argument one more time, because I think this is the crux of the entire problem. Before I do, let me just say I don’t personally have any problems with Go’s syntax one way or the other. I’ve learned a plethora of languages in my tenure as a software nerd and adding one more would not be a big deal if I felt the payoff was big enough. But I think syntax familiarity is a barrier for a lot of people, based on my experience as a language instructor and Parkinson’s Law of Triviality.
Briefly stated, Parkinson’s Law says we unfortunately spend disproportionate amounts of time and energy arguing about things that are more trivial (and we understand) than we do about those that are more substantial (and fail to grasp). This is particularly true with programming languages and syntax. I saw that resistance teaching Java to C++ folks back in the mid-90s. And that wasn’t exactly a big leap. Changing from C++ to Go is likely to be much worse than C++ to Java, and that resistance is critical to adoption rates.
So I’m not feeling the love for Go replacing C/C++ systems programming either. If I was looking for a new tool in my toolbox, I don’t think I’d be buying this one from Google.
All of this leaves me scratching my head and singing:
“Go! Huh! Yeah!
What is it good for?
Absolutely nothing.
Say it again.”
This article is translated to Serbo-Croatian language as well.
Google is initially aiming Go at their server farms. They want to write certain server software in a language that compiles and links far faster than C or C++. This Go does.
Secondly, the goroutines and channels will let them write concurrent/parallel software that will tend to be more correct than such software written with threads. Sure, you can pass an object pointer over a channel to another goroutine. But if one goroutine sets up the object on behalf of the next stage of processing (tiered execution pipelines), then it’s no big deal. The next tier will have exclusive use of what they’re handed over the pipeline. Yeah, you have to be more aware of what you’re doing – but it’s still preferable than trying to rendezvous on shared memory via locks. And you can always choose to send copies of data instead of pointers to data.
Another advantage of goroutines is that you can have massive numbers of them. This is something you failed completely to discuss. Your only distinction of messaging vs Java threads was the locking of shared memory of the latter. Yet goroutines are designed to be used in a single process to the order of tens of thousands. Threads of languages like Java, C#, or Scala are based on underlying native OS threads. An OS these days can have hundreds, and even a few thousand threads, but eventually performance and resource consumption causes performance to drop off precipitously. Forms of concurrency that rely on fewer OS native threads can scale much better. This is where Go looks to triumph as Google has an example program that starts 100,000 goroutines in a single process and harvest a value from each one. That much concurrency activity (within a single process) would be tough to do in other languages other than Erlang.
You really do make too much of the syntax issue by far, BTW. Adobe ActionScript3, which is used in Flex programming, has the same declaration style as Go – variable name followed by type (as does Pascal and PL/SQL). Java programmers that take up ActionScript3 programming (and gobs of them have become Flex developers in last 2 or 3 years) just about never voice this an issue.
Also, in Go, 90% of the time you just declare variable name and ‘:=’ assignment operator, which does type inference, like so:
parts := Split(“bob,jane,fred,sally”,”,”,0)
instead of:
var parts []string = Split(“bob,jane,fred,sally”,”,”,0)
and then something like:
for part := range parts {
fmt.Println(part)
}
instead of:
for var part string = range parts {…
IOW, the syntax of Go is actually very convenient, very, very easy to learn, and just not a big deal at all as you make it out to be. Tons of Java/Flex developers in enterprise development demonstrate the fact of just how utterly trivial the matter is.
Because you’re so far off on this syntax matter, and yet put a big deal of emphasis on it, it is cause to more deeply question your other analysis points. And so indeed, the fact you so missed the distinction of goroutine concurrency/parallelism relative to threading based on one-to-one native OS threads of other languages is yet another such question mark of your overall critique.
Okay, I’ve got some Go code executing 6 times slower than comparable C++ code, yet my C++ process can fire up a maybe a few thousands threads, but then brings the OS to a standstill. My Go program, in contrast, cheerfully fires up tens of thousands of goroutines. Think of the context of what Google does on those back-end data center servers. Which is truly being the most performant language in terms of solving the problem?
I really think your concluding remark to this piece is therefore flippant without having earned the right to be so. Some of your points were just too weak.
Go is a boring offering. Just because you hire the Programming Forefathers doesn’t mean that everything they produce is going to be gold. The free “marketplace” will decide whether Go (or any other technology) is worthy of use. Every programming language that gets used extensively does so by making some aspect of development easier for the programmer. Go seems to be nothing more than just Java-izing C/C++, or C-ifying Java. (features, not syntax) New languages do deserve consideration to see if they solve some pain point in the development process without introducing an unacceptable amount of new pain. Go doesn’t seem to introduce too much new pain, but since it doesn’t bring anything new to the table, what’s the point? Unless Google’s name itself is supposed the be killer feature…
Intresting information
i don’t think anyone should switch to go from c or c++, BUT for students and programming newbies they should definitely go for it
@RogerV:
Yes, Go does this. The benefit, however, is questionable. Is it more valuable to get a car off the assembly line 50% faster if it’s still slower than the one I waited longer for?
My experience with teaching students from C to C++ (1995-1997) and C++ to Java (1998-2005) shows about 25% will struggle and reject the language on this basis alone. And that’s with a language that is already very similar in syntax. Forward declarations are but one aspect of Go’s different approach, and perhaps the most benign.
I don’t think your language example underscores the significance of the syntax between the two. ActionScript’s heritage is much closer to Java than Go’s is to C++. Compare these two blocks of code:
SexprParserRef := MakeRef();
ManySexprs := Action(Many(SexprParserRef, 1), new(VectAction));
ListParser := Second(Seq([]Parser { Lp, ManySexprs, Rp }));
Sexpr := Alt([]Parser{ ListParser, SymParser });
SexprParserRef.SetTarget(Sexpr);
To this one:
void main()
{ int i;
char *inp;
clrscr();
printf("enter the regular expression :");
gets(inp);
nfa(1,0,inp);
printf("nstate input staten");
for(i=0;i %dn",ret[i],ret[i+1],ret[i+2]);
printf("n");
getch();
}
As far as the goroutines go, you said:
Which simply reiterates the point I made about the dangers of concurrent programming with Java. You still get free reign to do dumb things, like addressing local variables, because the Go language doesn’t preemptively stop you from shooting yourself, nor does it educate you why not to. If the purpose of moving away from C++ to Go is to get safety, this is a poor move. I’d love to see numbers on the goroutines you mention–an actual code example that fires those up and doesn’t bring the OS down. No one has addressed that to date.
And finally, I think you make a very compelling point: Go probably was created as a special-purpose language to run Google’s own server farms. But that is a far cry from a general purpose systems programming language, which is the argument I made above.
What has attracted me to Go is the feature of goroutines and channels as an abstraction approach to programming concurrency – especially with the potential of concurrent routines being so cheap (i.e., many goroutines multiplexed to relatively few OS native threads).
The only other two languages that offer something comparable to this and have enough of an established following that I might bother to learn them are Erlang and Scala (I don’t pay much attention to the Microsoft camp of F# et al languages.) Erlang, despite CouchDB having been written it it, is rather too odd. Scala I started getting into and then got bogged down in the functional programming side of that language. Overall it’s a rather complex language with a lot of turf to cover.
Then when I came across Go – well, it was a much simpler language to learn. Having programmed a good deal in C in bygone years, there was a lot about Go that had a sort of C sensibility about it.
It is a very young language, though. The one area that grates the most (coming from a Java background) is the lack of exception handling constructs. There is no way to catch and handle exceptions like dereferencing a nil pointer, divide by zero, array index violation.
So it is not possible to write an app server in a Java-like manner where all code runs in a single process (including loaded beans). Instead, one would need to rely on the POSIX fork() system call to launch any worker code as a child process and have the parent process monitor it in watch dog fashion. If any child processes panic fault then the parent process would detect and restart the process.
So far Go only supports unix/linux/Mac-OS-X OS where fork is natively supported. Windows API doesn’t expose fork() but it is available on the Windows POSIX dll. Hence Go will probably be better suited implemented on top of one of the various Windows POSIX runtimes.