All languages end up with simple concurrency primitives such as async/await.
No one takes the next steps and introduces the high-level primitives you actually need to work with actors and concurrency in a sane manner: monitors, messages, supervisor trees. Erlang has been around for thirty years, people.
Erlang isn't async. The actor model is great because you only have to think in single threaded mode. And with immutability being a core language feature, data races and other concurrency issues are literally impossible.
Because erlang is “weird” and not enough programmers learn it for it to have breached the cultural ramparts regarding what concurrency is in a programming language. I learned Erlang and Elixir and I’ve never been happy with any other languages’ concurrency mechanisms and primitives since then. Between multitasking features that let you avoid concurrent tasks causing CPU starvation, message passing allowing proper decoupling of concurrent tasks in both an asynchronous and synchronous ways and all the other little ways it does concurrent programming right… nothing holds a candle to it. There are some nice libraries in other languages but it’s not the same because it’s not built into the language at the same level.
Async/Await, asynchronous IO, none of this is really the same kind of “concurrency”… it’s why I wish I had more chance to use the Erlang/Elixir+Rust combo… low level safety and high level concurrency are a match made in heaven.
The fact that Erlang has existed since the 80's really begs the question "Why do language designers keep fucking up concurrency?". It's a feature that's really painful to tack onto to a language after the fact (looking at you, Python and JavaScript), but is absolutely necessary for any programming language.
I see goroutines as a solid "next best thing" after BEAM Processes, both of which are miles ahead of async/await, which is admittedly an improvement over any lower-level thread manipulation.
I have no problem using Erlang when I need it, but eventually concurrency is a problem that every language is going to have to deal with more effectively than it does now. The Actor pattern makes a lot of sense to me conceptually, and makes it trivial to parallelize systems. It's not like Erlang's the end all, be all of programming languages, but it is a forward looking one. I look forward to other languages catching up with it.
Not at all. Erlang's approach to concurrency has been well-researched and validated (Akka).
Async, await and friends are mere standardized kludges - popular syntactic sugar without clear semantics and real world connection (explicit message passing mimics how biological systems do self-regulation).
So called enterprise languages, especially C++ are full of similar stuff (kludges).
Adding on to what other's have said, I'll mention that while Go's concurrency features match Erlang's concurrency primitives pretty closely (`go routine()` compared to `spawn(fun routine/0)`, Go channels compared to `Pids ! {message}` and `receive`), almost nobody who does work in Erlang uses those primitives. Most concurrent/distributed systems in Erlang are built on OTP, the set of libraries built on those primitives, which has it's own set of higher level tools and abstractions (supervisors, gen_servers, FSMs) that provide a lot of the failsafes and profiling built-in. Basic Actor concurrency is simple in principle (but like most things in distributed computing) extremely hairy in practice, and OTP's libraries and templates take care of almost all of it (a reasonable analogy might be naked C++ vs. C++ with the standard libraries and Boost -- you CAN implement your own raw pointer-mungling data structures, but almost nobody does).
The erlang/go concurrency model is the most overrated paradigm ever.
Sure, the abstraction isn't leaky... Because there is barely an abstraction at all. Synchronizing state between independent processes is a very real, very unfun problem when all you have is the actor model.
For what it's worth, all of Facebook.com fetches its data with async/await (effectively promises+data) which is a nice sweet spot and a lot better to work with than actors.
I haven't checked Erlang too well, but is it so that the concurrency in Erlang software is basically actors only? Of course in this space you can also use Akka and even Rust and C++ have actor libraries available.
But there are definitely use cases where you don't want to use actors, where you might want to compose several futures together without the overhead of actor mailboxes.
OK, OP was somewhat remiss in saying "no-one". But you have, I think, missed his point.
Instead, substitute "few mainstream language designers" and it stands up. By mainstream I mean Java, Javascript/Typescript, C#, C, C++, Python and such. Most have introduced async/await. None has meaningfully gone beyond that as far as I'm aware. Working with Erlang's concurrency model is a refreshingly simple, consistent mental model compared to the mismash of concurrency features provided by the mainstream. In Erlang, it's as simple as:
No: regular functions.
Yes: are there only a few, and/or do I need strong isolation?
Yes: use OS-level processes
No: do I want the OS to take care of scheduling / preemption?
Yes: use threads
No: use async/await
Is there a chance that my async operations will be scheduled across multiple OS threads?
No: get speed boost from no scheduling overhead, but remember to yield if there's any long-running actions.
Yes: build my own likely-buggy, half-baked scheduler
Oh, and as a bonus: run back up the entire call stack to make all functions that call mine async.
And that's before we get to error handling. I'd take Erlang supervision trees _every day_ over trying to figure out which nested async callback function generated an exception.
That all sounds excellent. I've never actually had the chance to use Erlang, but I do have experience with concurrent applications in general.
I think concurrency will be the norm in the future, so I'm excited by things like Erlang, even if I've never had the chance to use them. I just want to make point out that a language like Erlang makes solving a hard problem easier, but it's not the solution itself.
this. Erlang's concurrency support is one of those things you can't unsee. Going back to sequential-by-design languages (which is pretty much every other industrial quality language bar go[1]) just feels cumbersome:
C/C++/C#/Python/...: "You want concurrency? Sure. We have OS processes, and threads, and this cool new async doohickey. Pick whatever you fancy! Oh, but by the way: you can't use very many processes cos they're _really_ heavyweight. You can have lots more threads, but not too many, and beware corrupting the shared state. Asyc though, you can have _loads_ of things going on at once. Just, y'know, don't mix the colours up".
With Erlang/Elixir it's just:
"You want concurrency? Sure, here's Erlang processes. You can have millions of them. Oh, you need to communicate between them? Yep, no probs, messages and mailboxes. What's that? Error handling? Yep, got that covered too - meet the Supervisors"
--
[1] Counting Elixir as "Erlang" in this context given it also sits on the BEAM VM.
Certainly - I expect that some day, there will be a "script" type language that gets a lot of what Erlang gets right with regards to concurrency.
It is not, however, an easy problem, as Erlang's real strength (IMO) is its runtime. In other words, I don't think you can just slap a few things into some other language and call it good.
I can't recommend Erlang enough as a way to teach concurrency. It was far ahead of its time while still being an incredibly practical language compared to Haskell, which I attribute to the fact that it was built to solve a specific problem (keeping telecom equipment running forever).
Erlang effectively makes everything asynchronous, so you're forced to deal with it. It's not glossed over at all, although it does give you good primitives to cope with it.
Isn’t erlang a very different, almost opposite concurrency model? I’m not an erlang expert but async message passing is a very different style. The limitation around background tasks in structured concurrency is trivial in erlang for example
Erlang has a very nice concurrency approach, particularly if you are into distributed and fault tolerant systems.
But it's ridiculous to say that "only Erlang can do concurrency". Many other languages do concurrency very well in slightly different ways (Clojure, Scala and Go, for example).
The problem is that Erlang and its BEAM-based descendants still seem to be the only languages that actually do get concurrency completely right. Lots of languages have some form of an actor model, sure (whether as libraries or - like Pony - baked into the language), but all of them seem to rely either on OS threads per process (which are obscenely heavy) or green threads / coroutines (which lack preemption) (if you happen to know of any other languages/runtimes that offer lightweight preemptive concurrent actors/processes, let me know).
Until that happens, BEAM is unfortunately a hard dependency on getting the concurrency model fully "right".
No one takes the next steps and introduces the high-level primitives you actually need to work with actors and concurrency in a sane manner: monitors, messages, supervisor trees. Erlang has been around for thirty years, people.
reply