Full laziness I found quite overrated while trying to write several very small business services in Haskell. Even in Elixir when you can utilise laziness in limited areas (in the I/O processing stdlibs, but there are almost no data structures for it) it's a proven fact [with benchmarks] that unless your data is at least a list with 500+ elements then laziness introduces both performance penalty and complexity. Not bashing the idea but it's not so universally good as several groups of rather religious programmers seem to make it. Right tool for the right job and all. ;)
Macros is Elixir are quite powerful and very different from stuff like it's done in Ruby. They are basically compile-time code generators, utilised with crushing success in Phoenix (web framework), Absinthe (GraphQL) and Ecto (DB data mapper library). Friendly programmer advice: don't underestimate Elixir macros. Many people stayed with Elixir mostly because of them.
---
> When the JVM finally supports preemptive multi-tasking, Erlang and the BEAM will become completely unnecessary.
1. Maybe, but I was hearing about preemptive multi-tasking on the JVM when I gave up on Java and that was around 2009. Believe me when I tell you, I really want at least 4-5 other runtimes to gain the capabilities of the BEAM. But alas, they still don't. Only Rust 3rd party runtime devs seem to be truly trying to push the envelope. Everybody else is like "yeah, we're gonna get it done by 2050, no worries". Sorry if that comes across as a bit cynical and dismissive, but I do read history.
2. The preemptive multi-tasking of the BEAM is indeed a huge selling point but not the only one. The actor model -- basically green threads with message inboxes -- are historically being proven more and more as a much more successful parallel computing model compared to... pretty much anything else. Really good Golang devs can kinda-sorta-partially emulate that with channels and mutexes/semaphores but it's obviously manual and error-prone. Rust's `actix` devs also agree and if you look at Techempower's benchmarks that try to emulate real web apps, you'll notice that `actix-web` is on top. Kinda funny when you think about how many people here in HN keep saying the actor model is only a good idea on paper and would never perform well in practice.
Additionally, if you keep an eye on the whole ecosystem (as much as that is actually even possible) you'd notice that almost everyone, JS included, is begrudgingly moving to immutable data and lock-less synchronisation. A lot of tech is starting to come to grips with the reality of us humans being flawed and not as bright as we'd like -- me included. I paid my dues with manually crafting mutex and condition variables workflows in C for years, then translating that to Java, then Go, etc. And I can confidently say: it doesn't work sustainably well. You can make a few simple pieces with it but for long-term projects, just go with immutability and lock-less sync.
---
I guess my point is, Erlang/Elixir are still quite strong and don't have much serious competition in their niche (where they are doing well).
Lastly, I agree that the BEAM in general isn't the fastest thing to run code on. Absolutely. In practice however -- and I mean importing a few million lines of CSV/XML a day -- I found that if you invest just a little more effort, Elixir will stay out of your way and your code will be mostly I/O bound. I mean yeah, Elixir isn't as fast as C++ or Rust. But I already used it for several pretty different projects and it has been performing absolutely excellently.
I am looking forward to learn Rust's `actix-web` though. I feel it could be a better fit for some more dramatically more computationally demanding web projects.
If Rust gained all BEAM capabilities I'll switch tomorrow, dude.
At the moment though, Elixir is just the only choice for excellent parallelism and concurrency.
I know Rust is working hard to get there. It's not there yet though.
Quite frankly most of the multithreading things an synchronization is quite simple and does not bother me except some rare cases (dealing with DirectShow for example). If some languages fail to support real world constructs directly it is the problem of their designers and users. All this stuff about horrible, horrible manual memory management and awful synchronization issues is overblown I think.
They were exaggerating of course -- and they were like gods, they fixed hundreds of sync bugs in C code, mixed with assembly for like 15 embedded platforms.
I am not such a hardcore programmer like them to this day even though I am almost 40 but the mutex/condition_var combo has bitten me many, many times. Spurious wakes, for example: not all platforms do them right (side note: I realise these may remain a forever fact of life and be a key to having preemptive scheduling like in the BEAM VM [Erlang/Elixir]). A lot of defensive coding is needed. And that's only one example out of dozens.
IMO you are just used to it. If you code in Erlang/Elixir on very parallel-friendly projects I am pretty sure you'll never go back to the pthreads model!
It's just the conclusion of the group of programmers to whom I philosophically belong (basically people who ran away screaming from C/C++ after working 2 to 10 years with them) that this stuff looks deceptively easy and it works quite well in many cases... until the projects gets big, many people get involved and bugs start to creep in. In such conditions, immutability + actor model have so far proven to be much more people-friendly paradigms that make introducing certain class of bugs much harder.
Sure thing, I have just stated my personal opinion, not looking for anyone to agree. To each their own. Everything has a price, immutability/actor included. The rest is all about the trade-offs one is willing to make
I am looking forward to see if the Rust community will manage to make a statically-typed BEAM-like runtime with much stronger performance characteristics. That would be amazing.