Here are some potential reasons (I obviously don't know the actual reasons). You won't like any of them, but I hope you can take me at my word that I'm not a partisan (I have a passing familiarity with Erlang that comes of maintaining a Riak cluster, and I've built some fairly large projects in Golang, but my core languages are C and Ruby).
* Golang has a more conventional, familiar, boring, "safe" language design than Erlang does. If your current language is Python, you're apt to find Golang congenial; I describe Golang to my friends as "a modernized hybrid of Python and Java".
* Golang has a more flexible concurrency offering than Erlang. It has a very flexible (statically typed, sync-or-async) first-class channel type that you can deploy anywhere in a program whether you parallelize it or not. More importantly, it has first-class support for "conventional" shared-everything concurrency with mutexes and semaphores and whatnot. If you're designing everything from scratch to fit your language's preferred idiom, this may not matter, but if you're porting an existing design it might matter a great deal.
* Golang has what I will perhaps hyperbolically refer to as first-class support for strings, with reasonably performant regular expressions, a clearly delineated "just a bag of bytes" type designed from scratch for high-performance buffering and packet framing/demux, and a sane approach to UTF-8 Unicode. It also turns out to be a very elegant framework (as imperative languages go) for building parsers, since you can put the concurrency stuff to work for it. These are common programming tasks and not one Erlang is well known for handling gracefully.
* As I understand it, both Erlang and Golang have comparable lightweight process/thread/coroutine/whatever facilities. Golang was designed from the start to handle huge numbers of demand-spawned threads with small, dynamically allocated stacks. I'm not saying Golang does this better than Erlang does, but it might be tricky to argue that Erlang's process model is better than Golang's.
* Erlang requires an installed runtime and executes in a VM. Golang produces native binaries. You can compile a Golang program on one machine, rsync that single binary to another machine that has never been blessed with a Golang installation of any sort, and run it without a problem.
* Golang has modern, extremely high-quality tooling. Entire huge Golang projects rebuild in seconds or less. The compiler is extremely helpful. Code formatting and documentation are first class problems for the toolchain. The Go package system is well thought out, and, again, is familiar to Python programmers.
> Golang has a more conventional, familiar, boring, "safe" language design than Erlang does.
Do you mean "safe" as in "nobody got fired for buying IBM" or as in language making hard to start thermonuclear war by accident? Because Erlang, with it's immutability everywhere is as safe as, or safer than Go.
> Golang has a more flexible concurrency offering than Erlang.
Basically everything you wrote here Erlang has. And what they were porting was in Python + GEvent, which means no threads anyway.
> a clearly delineated "just a bag of bytes" type designed from scratch for high-performance buffering
Erlang's binaries and strings (two different types) are designed for the same thing.
> but it might be tricky to argue that Erlang's process model is better than Golang's
Well, Go did a nice job borrowing Erlang's solution here. As it origins from Erlang, it has to be good. ;)
> Erlang requires an installed runtime and executes in a VM. Golang produces native binaries.
Erlang is able to produce a single binary. That it contains a VM and libraries and user code is another matter, but rsyncing Erlang binaries is also possible.
> Golang has modern, extremely high-quality tooling.
Dialyzer, EDoc, various process viewers, debuggers and so on for Erlang are really mature.
I think that familiarity of syntax, familiar programming paradigm and raw (single threaded, number crunching) speed were the reasons. Go has many benefits over Erlang in the realm of marketing, but I don't believe Erlang is much worse a language because of it.
I meant "safe" in the "nobody got fired for buying IBM" sense. My sense of it is that from now until the heat death of the universe, Golang developers will say that language is safer because of its type system, and Erland developers will say that language is safer because of share-nothing and immutability. I think both languages are safer than Python.
But then, you cannot have it both ways. Either Erlang is "safer" because of share-nothing and immutability, or Golang is more flexible w/r/t concurrency. I can design a shared concurrent data structure in Golang that is protected by locks or atomic counters, and I can do that easily, using the native first-class facilities of the language. Can two Erlang processes cooperate using a single shared buffer with a custom-designed concurrency scheme? Is that a natural thing to express in Erlang? It's a natural thing to express in Golang.
I feel like you didn't really engage with the string processing point I made.
I feel like it doesn't help an Erlang advocate's point too much to observe that Golang stole the best parts of Erlang.
I feel like every time it is ever pointed out in any language comparison that Golang can produce runnable native binaries, someone always has some rube-goldbergian alternative that nobody in the real world ever uses to get their own language bootstrapped onto some routine from a single file.
I gave specific reasons why Golang's tooling is strong. I feel like I got a response that says "Erlang's tools are mature". Nobody is arguing that Erlang is immature. The argument is that it's geriatric. :)
Ultimately, I agree that most of what I think is good about Golang is probably icing on the cake after "the language is boring enough to be familiar to Python programmers".
> This is a taskbar button press for me.
I'd hate for anyone to lightly brush off this feature. The fact that you can you can just rsync a binary means you can just spin up a machine, not care about what libraries are installed, and just run the Go binary on it.
I know there are tools like Chef out there, but I can spin up production-ready Go application servers on any Linux box in a minute because of this feature.
Erlang shows, logs, send via mail and telepathically tells you about what died where with all the details, and then additionally restarts the failed process according to restarting policy and tries again. Or not.
Anyway, I think this thread was about comparison of Erlang and Go - other threads are already full of people writing how wonderful Go is. As a part time Erlang developer, in this thread, I'd like to read what Go has better than than Erlang, not what is good in Go in general, because the latter is just increasing noise-to-ratio.
And it's possible to build single binary and deploy it with Erlang too.
Static typing with a very convenient expression in the language.
A concurrency model that is easier to adopt if your frame of reference is concurrent C++.
A simpler, friendlier syntax, which is probably not a win if you're a veteran Erlang programmer.
Probably better tooling: native binaries, a lightning fast compiler with great error messages and testing facilities, &c.
Perhaps a more modern standard library, which is made somewhat simpler and more concise by the pragmatic adoption of a very little bit of conventional OO, without going whole hog the way Java does.
They can be. By default a `make(chan int)` is blocking, but you can give it a buffer size with `make(chan int, 1000)` or something and it won't block until it's full.
When this happens, it seems like it tends to be exposing a fault in the design of the program. In a purely asynchronous system you can obviously avoid deadlocking in interprocess communication while still having a system that never correctly converges.
Sure, a program that uses a channel with a large buffer size as if it were an asynchronous channel contains a bad bug. The point is that if you need such an asynchronous channel, Go doesn't provide it. There are many possible examples of programs that need truly asynchronous channel functionality in which using a channel with a large buffer size would expose the program to subtle deadlocks that may only manifest in the wild on large data sets.
Wouldn't a correct design for programs that occasionally needed to handle huge data sets be to consciously and deliberately serialize (or at least bound the concurrency of) some parts of the code, rather than to pretend that the program was operating on an abstraction that could buffer arbitrary amounts of data in parallel and always converge properly?
Yes. You can always build the right thing in a system with synchronous channels—there are many ways to build asynchronous channels out of synchronous channels, after all, even if they aren't built into the language. My point is that asynchronous channels make it easier to avoid accidentally shooting yourself in the foot, that's all.
For what it's worth, I don't think that Go made a bad decision here (although I personally wouldn't have made the same decision, because of examples like those I gave in my other reply downthread). Certainly synchronous channels are faster. There are always tradeoffs.
If you want async, you could really just keep consuming from the channel with goroutines until your hardware catches on fire. There's nothing in Go that is limiting this behavior.
Async communication makes it harder, but doesn't avoid it by default. E.g. if in in Erlang gen_server A calls gen_server B w/o timeout and B, to process this call, then calls A (ouch, bad design, but possible), you've got a wonderful deadlock.
I'm using both, Erlang/OTP and Golang. Both have their strengths and advantages. So simply use the right tool for the right work (and no hammer to turn a screw).
Right, you can deadlock in any actor-based system (well, not any actor-based system—I've seen research systems that provably do not, but they're research). Async communication just makes it harder to screw up, as you say.
My point is that there are actually very few concurrency problems where deadlocks are solved by increasing the buffer size by some fixed amount. If you want your code to be correct, in most cases a buffer size of 100 might as well be a buffer size of 1, except that an increased buffer size can improve performance for some scenarios.
When people talk about asynchronous channels, they usually mean that you can stream messages to another actor and know that you won't block. That is not true for Go channels. You can increase the buffer size, but that just reduces the chance that your program will deadlock: it doesn't make a Go channel work in situations where you need an asynchronous channel for your program to be correct.
then your normal program flow won't block. I guess that's what you mean by deadlock. If your program runs into an actual deadlock, the runtime will detect it, crash the program and show stacktraces.
That just gives you more complicated deadlocks. You still have to be aware of the potential for tasks to deadlock and consciously design them not to do that. It's a problem that does come up all the time in Go programs, but tends to come up quickly enough (due to the way concurrency is designed in Golang) that you fix it quickly, like an accidental nil reference in a Ruby program.
* Golang has a more conventional, familiar, boring, "safe" language design than Erlang does. If your current language is Python, you're apt to find Golang congenial; I describe Golang to my friends as "a modernized hybrid of Python and Java".
* Golang has a more flexible concurrency offering than Erlang. It has a very flexible (statically typed, sync-or-async) first-class channel type that you can deploy anywhere in a program whether you parallelize it or not. More importantly, it has first-class support for "conventional" shared-everything concurrency with mutexes and semaphores and whatnot. If you're designing everything from scratch to fit your language's preferred idiom, this may not matter, but if you're porting an existing design it might matter a great deal.
* Golang has what I will perhaps hyperbolically refer to as first-class support for strings, with reasonably performant regular expressions, a clearly delineated "just a bag of bytes" type designed from scratch for high-performance buffering and packet framing/demux, and a sane approach to UTF-8 Unicode. It also turns out to be a very elegant framework (as imperative languages go) for building parsers, since you can put the concurrency stuff to work for it. These are common programming tasks and not one Erlang is well known for handling gracefully.
* As I understand it, both Erlang and Golang have comparable lightweight process/thread/coroutine/whatever facilities. Golang was designed from the start to handle huge numbers of demand-spawned threads with small, dynamically allocated stacks. I'm not saying Golang does this better than Erlang does, but it might be tricky to argue that Erlang's process model is better than Golang's.
* Erlang requires an installed runtime and executes in a VM. Golang produces native binaries. You can compile a Golang program on one machine, rsync that single binary to another machine that has never been blessed with a Golang installation of any sort, and run it without a problem.
* Golang has modern, extremely high-quality tooling. Entire huge Golang projects rebuild in seconds or less. The compiler is extremely helpful. Code formatting and documentation are first class problems for the toolchain. The Go package system is well thought out, and, again, is familiar to Python programmers.
Just some guesses as to reasons in there.