BEAM+OTP is a masterclass in using concurrency to achieve fault tolerance. But Go achieves its "magic" by feeling like the lingua francas of programming, C and C++. Go doesn't make the developer learn too many new concepts. The runtime is self enclosed in the final binary. This commitment to the familiar programming patterns also means it allows for concurrency anti-patterns like shared memory which for Erlang+OTP's design principles is verboten.
Slightly irrelevant but that's a part of my issue with Go. I personally feel the chances are slim that "familiar programming concepts" (i.e. as taught by most intro CS courses) are optimal by themselves. And I know it's an old thing, but the fact that Go was once adamantly against generics...
The Go team as a whole was not adamantly against generics though, as I recall. Rather, they were against implementations that would have bad overall implications for the language (especially its complexity, both in usage and in implementation).
Once a sufficiently good proposal was made, generics were adopted.
It was considerably more messy than that but I don't want to dredge up old drama in detail.
I agree with everything you're saying. I think it comes down to design philosophy. Erlang's ecosystem is well tuned for building fault tolerant systems and features concurrency heavily to solve for that. Go is for general purpose programming in big organizations with massive variance in developer experience that has concurrency as a first class concept for the ability to scale (among other things).
Of course, in some sense fault tolerance and scaling are two sides of the same coin. They're both measures of availability. They're just different approaches to that.
What Go achieves that Erlang doesn't is the ability to "pick up and play". What Erlang achieves that Go doesn't is a pathological commitment to the system whole never going down.
The irony is that it ended up more complicated than it neeeded to be because it was added on later and had to be backwards compatible. I think if go had had generics from the beginning it could have had a simpler design. And go wouldn't have needed magic functions like make and len that are kind of generic, but not in the same way as user-defined generic functions.
> I personally feel the chances are slim that "familiar programming concepts" (i.e. as taught by most intro CS courses) are optimal by themselves.
On the other hand, Erlang has been out for ages and has largely failed to attract much adoption, so it doesn’t seem like the market finds it to be “optimal” either. Not that popularity is everything, but over time a language better languages should increase their market share, especially if your language got its start during an era where the competition was C and C++ and Java.
> And I know it's an old thing, but the fact that Go was once adamantly against generics...
Erlang not only lacks generics, but it lacks any static type system at all…
Rather than entire languages, I'd say that feature adoption is more likely the better indicator. Like generics, first-class functions, lambdas, error-handling (I'm partial to monads like `Result`), etc.
If one wanted, they could put ecosystem tooling here as well (e.g. `gofmt` saving everyone time and mental health).
Also, to clarify, I'm not arguing that Erlang > Go, I don't (purposefully) use either, though I have to read Go sometimes.
Erlang is slow for compute.
And most software does apparently not need what it offers.
I mean, Java does it even more elegantly imo and if anything it is the most stereotypical oop programming language of all time.
Can you explain how you think Java does it more elegantly? That's a very surprising statement. Java didn't even do m:n threading until "Project Loom".
Java has structured concurrency.
This poster summarized it well: https://news.ycombinator.com/item?id=49864334
Not to mention its a lot easier to learn Go concurrency over Elixirs whole ecosystem. Also Go has a job market while Elixir job market exclusively consists out of senior level job postings that get handed over from Elixir job hopper to another Elixir job hopper. There is barely any reason to learn Elixir except for being fascinated by it.
Comparing learning one language's concurrency model with learning another language's entire ecosystem is incommensurable.
Having learned both Go and Elixir, I found Elixir easier to learn and a lot more enjoyable to work with. I'm not alone in this opinion. According to Stack Overflow's 2025 "admired" languages, Elixir scored 65.9% compared with Go's 56.5%; Phoenix was the most admired web framework of 2025 at 79% and has held that spot for the past three years.
Erlang/Elxir would be more popular if it compiled to native. BEAM VM is not that performant and programs also take more memory compared to Go.
Erlang is dynamically typed, so many of the performance costs are similar to a JS runtime and always fully deciding typing ahead of time is an undecidable problem.
In practice, this is why many such languages have JIT's (unless targeting a subset or an type-information enhanced superset like TS), there was a seminal OOPSLA paper in 1995 by Agesen and Hölsze (who worked on the JVM Hotspot compiler) that compared JIT's to AOT compilation in practice (the Agesen CPA algorithm isn't perfect but it's pretty good for the time and others have probed that it's an undecidable problem).
That said, they also had a historically bad performance story due to misjudgments in development direction, the interpreter was default and they twice tried to make "HPC JIT's", ie.. complex JIT's that tried to be "perfect" and focused on numerical code gains, they'd be good for optimizing a matrix kernel, yet fairly useless or even negative on more common code patterns.
OTP 24,25 and 26 took learnings from the JS runtimes and also added compiler hints (since they already had binary precompiled modules).
What still saves the OTP runtime is that many basic operations that would suck without a good performance story is handled by built-in functions, so like Python most practical programs works well enough even if the runtime is behind.
Well to use Elixirs concurrency model you kinda have to use the rest of the langs ecosystem and learn a shit ton more compared to familiar feeling langs like Go. For Go I dont have to learn its execution model, some VM specifics and whatnot.