Meanwhile, Rob Pike and his contemporaries did language research, particularly related to the semantics of CSP-style concurrency. Syntactically they were all C-like, as the Plan 9/Research Unix community all generally liked it.
Newsqueak was the first and it was a cross between C and with special syntax and semantics for procs (green threads). It was written for GUI workstation environments in mind, the idea being to easily build multi-seat applications. From Newsqueak arose Alef, which refined on it but had manual memory management. Then from Alef came Limbo, the language running on top of the Dis VM that formed the core of the Inferno OS.
Fast forward some years later, Rob Pike and some other Bell Labs vets are at Google. Some event happens which painfully reminds them of mediocrity in computing, that gives them the drive again and they resume right where they left from Limbo.
Go is born.
According to Pike's blog, the real motivating factor for Golang was how forbidding and painful Google's C++ build process was. A lot of Golang makes more sense if you look at it through this lens: above all else, don't be like C++.
You and I disagree in regards to a lot about Golang, but I think you're spot-on here. I've thought for years that it was interesting how yosefk's criticisms of C++ in the "Frequently Questioned Answers" directly correspond to decisions in Golang: "compile times are long" → "use the Plan 9 toolchain", "memory management is difficult and unsafe" → "garbage collection", "templates are a mess" → "no generics", "exceptions interact badly with RAII" → "no traditional exceptions", "header files are a pain" → "use packages and forbid circular dependencies", etc.
I never though to evaluate Golang against it. Great point.
Note that I don't think banning exceptions is really the answer; in particular, the destructor issue is just a specific case of "handling errors during finalization is really hard", and you can't get away from finalization in general. Exceptions really put those issues front and center, though.
Yes, that was the "spark" that motivated it, as I hinted it.
A lot of Golang makes more sense if you look at it through this lens: above all else, don't be like C++.
"Don't be like C++" is pretty much a side effect behind much of the Bell Labs and Research Unix philosophy that values composable byte stream interfaces and liberally using a small number of abstractions.
The historical context behind Go that I wrote about is quite undeniable, though. I feel that you're being a tad too contrarian here, but I'd love to know more from your viewpoint.
Having native CSP gives Golang a differentiator that it would not so clearly have without it. People can disagree about toolchain quality, and for every person that appreciates a well designed stdlib, there are 3 that appreciate CPAN more. It's harder to disagree with a facility that few mainstream languages provide in any form. So CSP is very important to Golang's identity.
It's just not the "why" of Golang (or at least, I don't think it is.)
See this excerpt from the Alef reference manual [1]:
chan(Mesg) keyboard, mouse;
Mesg m;
alt {
case m = <-keyboard:
/* Process keyboard event */
break;
case m = <-mouse:
/* Process mouse event */
break;
}
Now where the toolchain is concerned, again that was adapted from the Plan 9 compiler collection (which even OpenBSD at one point was considering but backed off due to licensing) which makes cross-compilation a surprising breeze.Carefully designed standard library? Plan 9's syscall interface...
Composable APIs defined by one key abstraction? Plan 9 syscalls again, though there it was 9P.
Speed was a motivator, but again - direct side effect of the "5 Principles of Programming" espoused by Rob Pike [2].
When I jumped ship from C to Java, Java's object orientation wasn't exciting to me, and its exception handling is an acquired taste.
But dynamically growable, garbage collected buffers are something I'd missed for a long time. And the simple ability to concatenate strings without first reserving space for the result. Oh, and hash maps! Remarkably versatile data structures, those.
Coming from C, Java was a delight. Java would have a lot more trouble dragging me away from Go.
Not exactly the same thing, but routine string manipulation in C gets considerably easier once you discover a highly underrated function called asprintf (basically combines sprintf and malloc, calculating the buffer size for you).
But I still need to worry about creating a memory leak with this. :(
Also, having a map implemented in a library is a Good Thing. It means that your language is extensible and expressive enough for this. AFAIK Go is - by design - not that extensible.
Auto-conversion: "2" + 5 = "25". This looks horribly hackish, like some type buggering perl might do, or js. But it comes in handy when you want to build a message string.
And yes, as the article tells us, a lot of things are very purposely left out of Go, which has advantages and disadvantages like most trade-offs.
string hello = "hello";
string world = "world";
string hw = hello + ' ' + world;
Auto-conversion: stringstream ss;
ss << "2 + 2 = " << 2 + 2 << endl;
string result = ss.str();"nice try" on "auto-conversion".
And this is a problem because?
(It's actually a weak point of Go that you cannot define them in a library without sacrificing type safety.)
C++11 has a GC API defined.
Reference counting is part of any GC book in CS speak.
However, I feel that doing the "implicit casting" thing only for the single, limited case of string concatenation strikes a happy medium between providing useful convenience and giving you enough rope to hang yourself with.
But it is infinitely better tasting than Go's ridiculous error handling which is something you would expect in the 1980s.
If your sweet spot is 90~95% java and 5~10% C.
And, what about python programmers, how would Go be for them?
I can't deal with Go. And I don't think it's me--I don't do Haskell because of me, I don't do Go because of it. I find it almost impossible to think in Go. I find it incredibly primitive, well past the point of "stupid code is impossible to misunderstand" and into "stupid code because the language demands it." This wouldn't bother me, in a very "you do you" sense, if I wasn't stuck debugging faddishly-designed tools like Docker and Terraform written in it. To this end I think Go is a regression for the open source community, because what I see as veneration of stump-dumb languages makes it harder, not easier, to be smart about problems.
Since the parent mentioned C and Java. What are you missing in Go compared to Java besides generics? What are you missing in Go compared to C besides manual memory management?
To me, Go seems to have about the same amount of expressiveness as C and Java. The difference being that it's safer than C and more UNIXy/less OO than Java.
To this end I think Go is a regression for the open source community, because what I see as veneration of stump-dumb languages makes it harder, not easier, to be smart about problems.
A lot of open source UNIX software was written in C. To me it seems that if C was acceptable, Go is acceptable (if the application can live with a GC and slightly lower performance). And as the article argues, it lowers the bar for contribution, because it restricts overengineering.
That's a clever way to attempt to constrain the conversation away from the elephant in the room. "Other than the bullet in your stomach, how are you feeling?"
Not having at least Java-style "dumb" generics, in 2015, is unacceptable; the existence of `go generate` should mortify everybody involved with Go. Not having better than that--consider what you can do with Scala even before you get to something like Shapeless--is not quite unacceptable but short-sighted and limiting because suddenly I as a human have to do what a moderately smart compiler can do around type checking and leveraging types to solve problems.
Go's general ignorance, and the community's general ignorance, to really basic functional programming that so hugely improves your life is probably borne out of the stupid type system; things like composition (Try monads) for error handling, so I'm not vomiting `if err != nil` everywhere, things like functional transforms for data structures so I'm not writing for loops until my eyes bleed. And you can't really do that in a statically typed language without either blind casts (which Go partisans recommend, because clearly everything should be `interface {}`, remember the days when java.util.ArrayList just gave you Objects?) or generics.
It's just...dumb, written for the lowest common denominator, and I guess the lowest common denominator is dishearteningly low. Good for them, but having more and more core tools written in this junk makes my job a lot harder because it obfuscates potential problems under a sea of boilerplate and line noise.
> To me, Go seems to have about the same amount of expressiveness as C and Java.
I agree with that assessment. Go's roughly equivalent in expressiveness to Java.
That is a criticism, not a defense.
Go being a somewhat more terse Java 1.4 is not an endorsement of the language or the environment. I stopped using Java quite some time ago because my frustrations with "coding with gloves on" outstripped any benefits of the language. (Not the virtual machine. The JVM is fantastic, I love using it. But Java-the-language is Newspeak: if I can't coherently describe a solution in its syntax and semantics, I have to resort to worse solutions. Go's actually worse for this, surprisingly enough...)
Michael O. Church discusses the problems of Java and the problems if the Java shop very well in one of his articles, and in my experience the Go people I have worked with and talked to almost universally fit into that mold (echoing the normal Java ignorance of the outside world, a neat sense of epistemic closure, and the weird desire to rewrite the world into it).
https://michaelochurch.wordpress.com/2012/04/13/java-shop-po...
> if C was acceptable, Go is acceptable
Should C be acceptable? I don't think so. C is, in 2015 and in truth in 2000, too stupid to live. For a very long time we had no other alternatives, and it is an effective lingua franca because it's dumb enough that you can knock out a language binding in short order, but it's a bad language. No memory safety, no type safety (seriously, just review the rules for implicit pointer casting, you have no types to speak of), and nothing, anywhere, to help you not do things that are damaging.
Like, I'm not a C++ fan because it has many warts and creeping features, but if you literally limit yourself to C with classes, std::string/std::vector, and use pointers only in a last resort (preferring references), you have just solved probably eighty percent of the correctness and security problems caused by our reliance on C. (And you cannot practically implement many of those solutions in C without a level of developer discipline that essentially does not exist in the wild. Just having ctors/dtors is literally transformative to writing safe, smart code.)
Rust will solve more, better, and I'm a huge fan of what they're trying to do, but isn't there yet.
> And as the article argues, it lowers the bar for contribution, because it restricts overengineering.
That's an argument. I'd say that it restricts engineering. Which is not a fatal flaw of a tool, there are lots of problems where grunting and bashing your way through it makes sense, but engineering problems often require being able to actually write what you mean, not write what you need to address the symptoms of the inexpressive language before you get to write what you sort of mean if you squint through the garbage it forces upon you.
Lowering the bar for contribution is only a plus if it doesn't moronize people who are cool with clearing a higher bar. For most of the stuff that I deal with, four novices don't replace one expert. When using Go, I very strongly feel that I can't do my job intelligently because I don't have the tools, and so not only will I do my job more slowly, but I increase the likelihood of doing my job wrong.
For every post like this that has me starting to think "hell yeah, C is really stupid, how can others not see this?" I'm reminded of why Linus Torvalds is glad he didn't choose c++ for git. And... it resonates too bloody well. Especially when I consider all of the ports to other languages that have been attempted for git.
I think it comes down to generalities. The reality is most programs are doing good if they solve one problem. Not just solve it well, but solve it at all. Many algorithms, on the other hand, can be widely adopted.
This leads one to think they could "write with their gloves off" and nail down that algorithm in such a way that it will be usable everywhere. The reality, though, is that it rarely (ever?) works out. What you find is that all of the small corner cases that matter in solving something come back and bite you. Hard.
I agree and disagree with all your points. I have written C++ and Prolog professionally for years, then some Java (because employer), with a little Haskell on the side (hobby projects).
I am in a bind when it comes to PLs. I prefer the abstraction of C++ and Haskell (or Prolog for the domains where it fits). On the other hand, it is easier in powerful languages to get complete mismatches between the level of abstraction and the abstractions that are used. To take three widely-used C++ libraries as an example:
- Boost: highly template and template meta-programming driven.
- Qt: basically C++ as C with classes, with moc for signals. Really only templates for collections.
- Xerces/XQilla: 90ies style C++ with global state, and too many Java SingletonFactoryProxies.
In projects where you use different dependencies with different styles, things can get ugly. Also, your policy-based design may not be understandable to your 'C++ is C with classes' colleagues/contributors.
In the end there will always be interaction between expressiveness and maintainability/accessibility. The right abstractions can improve both. Too much magic (page-long type signatures, too many levels of templated indirection, etc.) can make everyone's lives miserable. The graveyard of ugly C++ libraries shows that finding the right abstractions can be hard, even for experienced programmers.
- `go generate` was never designed as a way to bring generics to Go.
- Most Go programmers are not "ignorant of basic functional programming". They use FP in other languages, and even in Go which has first-class functions, higher-order functions and closures. But it's true that the lack of generics severely limits the usage of FP techniques in Go.
- Go partisans don't "recommend" to stuff everything in interface{} and use "blind" type assertions everywhere. They even recommend the contrary. Give me a link to the Go official documentation that recommends that and I'll revisit my position.
To be clear, just like you, I sometimes miss generics in Go, especially when I'd like to use some FP techniques. But for me, it's just an inconvenience. It sounds like for you it's a showstopper and I understand that. But I don't think that using words like "junk", "stupid" or "dumb" helps in making your point.
I hope, and I'm confident, that the Go team will find a way to add some form or type parametricity that fits well with the overall language.
Unix was designed to port Spacewar. What's that got to do with anything?
> Most Go programmers are not "ignorant of basic functional programming".
That doesn't match my experience. The overwhelming majority of Go people I know, and the loudest advocates to whom I am exposed, seem to regard functional programming as a nothing. Your experience may differ.
> Go partisans don't "recommend" to stuff everything in interface{} and use "blind" type assertions everywhere.
Again, that doesn't match my experience; this was literally recommended to me by a senior-level Google engineer. To his credit, he suggested instead using `go generate` as an alternative. (Because that's better. =/ )
> I don't think that using words like "junk", "stupid" or "dumb" helps in making your point.
Completely fair criticism. But let me put it this way: I view Go, and the terminally blinkered Rob Pike, and his disciples, to be so obviously and monstrously disastrous to what I do for a living that those were the remains after a pretty heavy dose of editing and self-censorship.
I could tell you how I actually feel if you'd like. =)
Don't know about "very", but there would be very little difficulty moving from java to go. There wouldn't be that much value to it though (startup speed and deployment would be the primary ones, and if those are your concern chances are you're not using java as it's notoriously not great at those).
> And, what about python programmers, how would Go be for them?
That seems to be the primary actual market, migrations from python, ruby, php and the like: Go provides a bit of type safety and easy concurrency, an easy deployment story, structural typing is closer to duck-typing than nominal typing (where interfaces must be explicitly opted into by objects) and the fast compilation time means the compilation step isn't much of an issue over "direct" interpretation (/implicit compilation).
I have one more question, how does Go ensure easy concurrency?
Beware though, Go uses shared-memory concurrency (as opposed to, say, Erlang) so if you pass a pointer to a mutable structure through a channel the structure won't be copied or moved, both sides will be able to alter it. It does provide a data race detector but it's just that, you have to hit the corruption path while running the detector for it to have a chance, I'm not sure it's 100% even if you do, and I understand it has a non-trivial runtime cost and limitations wrt number of routines it can track.