For me it is Go vs Erlang. I see both solving similar set of problems (for me!).
The slides said Go is easier than Erlang. That is true in some aspects, namely syntax (Elixir to the rescue here!). Go is also easier because of static typing. Speed of compilation is awesome. Building to an executable that only depends on libc -- yes please! love that about Go.
I am scared about safety and fault tolerance. Ability to share memory is good for performance but a shared heap in a large concurrent application is scary to me. Not sure what I think about multiple channels and running select over them. Then it pseudo-randomly choosing one channel among those that can receive. Erlang's focus on processes/actors vs channel and each actor having a single mailbox somehow makes more sense to me. Having a shared heap mean faster data processing but GC cannot be fully concurrent.
Now passing channels inside other channels is cool, but also kind of scary to me. You can pass channels, inside channels, inside channels, can make some kind of a lazy computation chain.
Also I have been wondering, but couldn't find it by doing a quick search, is it possible to build supervision trees out of goroutines like one builds supervision trees in Erlang's OTP. Say I want to have a chat client goroutine to keep the chat up. But I want to monitor it in case it crashes (panics?) then then spawn another one perhaps. Is that possible?
As someone who has shipped production software in both Erlang and Go. They are very different beasts. Regarding error handling, Go is far closer to C than Erlang. If Erlangs slogan is "let it fail" and gives you the power to avoid writing error handling for every single thing, Go's is "don't let it fail" ... and you really need to write error handlers for everything, reducing the "unexpected" footprint.
There is no real way to grab a goroutine from the outside and tell it what to do -- you have to use its channels, which if bad things have happened are probably broken.. there are some systems built that catch exceptions and send messages (this is from inside the goroutine of course) on the channel, but I haven't used them.
That might come across an unduly negative of Go, but Go has major upsides. Great tooling, easy to understand after a tiny amount of time, a culture of explicit (even at times non-DRY) code, amazing deploy model, and generally just very understandable even to newcomers.
Interesting, thank you for explaining. The lack of monitoring of goroutines is certainly different.
> which if bad things have happened are probably broken.
It reminds me of Joe Armstrong's quote about how it is hard to perform surgery on yourself. In other words having the component that is failing trying to fix itself. I guess I would have to read more about design patterns. I saw a presentation about concurrency patterns in go, but it is about very simple toy examples, I am more interested in a larger concurrent applications, handling multiple connections for example.
Yeah... so far my Go stuff has had exceptional reliability, I verified I handled all error known conditions with errcheck (https://github.com/kisielk/errcheck) and just generally took the slow and plodding approach of handling everything explicitly. My app handles hundreds of thousands of concurrent connections, each one often using and/or spawning 4 or more goroutines.
I've found net/http package source code to be useful on this matter, as the package contains production-ready servers and clients implemented in Go itself.
Yes Erlang also has good libraries for that. My question wasn't as much about libraries as about supervision trees.
Having a part of your program fail and restarted if needed. For what I understand so far that isn't possible. It would have to be done at the OS process level instead.
When I'm using Go and have a goroutine which could possibly fail, I also return an error channel allowing the caller to handle errors from inside the goroutine.
I share the exact same sentiments as you, and, would also love to know if there is anyway to mimic something like the OTP supervision tree. One-for-one? One-for-all?
Not on the Go level. You can't guarantee memory safety after a panic since it's shared between the goroutines. It's also not possible to do code live-reload.
On the unix level it would be possible if your process manager supports dependencies between processes and you're able to connect pipes between them. This would also be much more heavy than erlang threads in terms of memory.
The slides said Go is easier than Erlang. That is true in some aspects, namely syntax (Elixir to the rescue here!). Go is also easier because of static typing. Speed of compilation is awesome. Building to an executable that only depends on libc -- yes please! love that about Go.
I am scared about safety and fault tolerance. Ability to share memory is good for performance but a shared heap in a large concurrent application is scary to me. Not sure what I think about multiple channels and running select over them. Then it pseudo-randomly choosing one channel among those that can receive. Erlang's focus on processes/actors vs channel and each actor having a single mailbox somehow makes more sense to me. Having a shared heap mean faster data processing but GC cannot be fully concurrent.
Now passing channels inside other channels is cool, but also kind of scary to me. You can pass channels, inside channels, inside channels, can make some kind of a lazy computation chain.
Also I have been wondering, but couldn't find it by doing a quick search, is it possible to build supervision trees out of goroutines like one builds supervision trees in Erlang's OTP. Say I want to have a chat client goroutine to keep the chat up. But I want to monitor it in case it crashes (panics?) then then spawn another one perhaps. Is that possible?