Of course there can be more distinctions, but those are very helpful for almost every case that I had to deal with.
Erlang's BEAM really nailes #3. The BEAM is just so cool, I'm surprised there are no similar products out there (if you know any, please tell me!).
Unfortunately for #2 I really don't like either Erlang nor Elixir. To nail 2, I found pure functional programming languages to be the best by far. They allow extreme precise control over concurrency on the same machine (be it single-threaded or multi-threaded), better than any other paradigm I've used (including actors for example). My preferred language here is Scala, but others are doing really well too.
I wish I could run Scala on the BEAM, since Akka (actors on the JVM) are just not nearly as good as the BEAM.
I am really interested in learning more about the libraries and abstractions you would use for #2 in Scala (or other FP languages). Could you provide some references so I can dig deeper? Thanks!
If you want to just learn it and have no prior JVM knowledge then probably Haskell is the best language to learn the concepts. You then want to first get an idea how to explicity describe and control effects (using the IO-type in Haskell). The next step is then to handle errors (with IO and Either types) and then how to handle effectful streams.
The combination of those 3 allows you to do things like "run those two processes at the same time, where one process does something every minute and the other when a request comes in. Then merge the two together, only execute one action per 30 seconds even if there are more events from the two combined processes. But if an action fails, retry it 3 times while waiting a few seconds between each try. If the 3rd try fails then, depending on the error, stall the process that runs every minute for 10 minutes and only accept events from the request-based process..."
And so on. I found that in languages that don't support those explicit (pure functional) concepts, it is almost impossibly hard to get the logic right when multiple levels of concurrency and error-handling come in.
If you have prior JVM knowledge or want to build something productive then I suggest to start with Scala and ZIO (https://zio.dev/) using the same concepts as described for Haskell.
Then afterwards, have a look into STM (https://zio.dev/reference/stm/ for Scala or https://hackage.haskell.org/package/stm for Haskell). Those essentially allow you to do things that database often do for you (fine grained locking) - just more powerful and composible and in-memory without database IO.
With those things you are well equipped to deal with problems of type #2.
Oh sorry, I guess I misread your post. But yeah, Scala alone doesn't make the difference compared to Elixir, it's ZIO or alternatively cat-effect. Scala as a language just enables those libraries to exist and be used ergonomically. I don't see a reason why something similar couldn't happen for the BEAM, but there hasn't be a language that supports those concepts yet.
1. No concurrency
2. Concurrency on the same machine
3. Concurrency between machines
Of course there can be more distinctions, but those are very helpful for almost every case that I had to deal with.
Erlang's BEAM really nailes #3. The BEAM is just so cool, I'm surprised there are no similar products out there (if you know any, please tell me!).
Unfortunately for #2 I really don't like either Erlang nor Elixir. To nail 2, I found pure functional programming languages to be the best by far. They allow extreme precise control over concurrency on the same machine (be it single-threaded or multi-threaded), better than any other paradigm I've used (including actors for example). My preferred language here is Scala, but others are doing really well too.
I wish I could run Scala on the BEAM, since Akka (actors on the JVM) are just not nearly as good as the BEAM.