> In what way?
In the ways I described below that line :)
> It's certainly not simple to set up! Most languages, I can put my projects wherever I want. It took me a while to find out that I had to put my projects in my Gopath for them to properly compile with third party libraries. There are lots of weird restrictions like that.
Python, C, and C++ all have magic directories just like that. For ex /usr/local/lib/python2.7/site-packages/
At least Go lets you define where to put it yourself, and the paths are just the URL for the VCS.
> Goroutine capture is by reference, which is why a lot of new people have trouble with goroutines in for loops.
I think you're talking about what happens when you run closures as goroutines in a loop, like this: http://play.golang.org/p/1NX39zk4NI
This is just a misunderstanding of how closures work and what it means to start a goroutine. Yes, closures capture the variables so that modifications inside the closure and outside the closure both affect each other, that's the whole point of closures. Goroutines, when started, may not start right away, and actually generally don't, certainly not faster than this loop can run.
> Go, like most imperative languages, can suffer from global variable overload. Lots of Go code is also so badly typed that it's impossible to tell what things are supposed to be. I can't tell you how many times I've seen `x := poorlyNamedFunctionWTFIsThis()` or `foo(x {}interface){... x.bar()}`
You can write bad code in any language. I don't think that's an indictment of go.
> There are `panic()`s.
Panic is intentionally clumsy and is actively discouraged. Any package that panics as a form of replacement for exceptions will basically never get used by the community. That's a big difference from other major languages that use exceptions for error propagation and control flow.
> Rust also doesn't even have null pointers at all, at least in `safe` code blocks. Rust uses `Option` instead.
From what I've read this is actually just inferior to Go's multiple returns, because options don't tell you why they failed, unless you use multiple returns, in which case it's basically exactly like Go.
Go:
val, err := foo()
if err != nil {
return err
}
Rust:
let (opt, err) = foo()
match (opt) {
(None) => return err
}
Is that really any better? In Rust you have to know what match does, what this magic (None) => business is... whereas the Go code just reads like normal C-ish code. Anyone who's ever taken intro to programming would be able to tell you what the Go code does. To understand the Rust code, you have to know a lot of the language internals. And that's exactly what I mean about Go code being simple and easy to understand.
> a lot of modern languages have [concurrency] primitives like this.
Not any of the mainstream languages. C, C++, Python, Ruby, C#, Java, Javascript .... some of them can do similar things, but it takes a lot more boilerplate and it's a lot uglier and harder to reason about.
[Edited for clarity]