That Erlang forces some synchronization that other languages may not does not affect the ability to (with versions of Erlang since, what, 2007 or 2008?) make use of SMP for simultaneous execution of processes on separate cores or processors.
See also OpenMPI for an example of a distributed programming system that also can't share memory without copying it. Though in its case it was across physical nodes (and so the need to communicate was more obvious, they physically didn't share memory anyways). Still true parallelism.
Being explicit about the data being passed around while defaulting to “not shared” has benefits for making use of all your cores more efficiently.
It seems that James Goslings view of "true parallelism" is "let you take advantage of multiple processors", so with that frame of mind, Erlang does give you "true parallelism".
> Coroutines kind of magically sidestep some of the naughty issues in true parallelism. And for me, one of the problems with coroutines, which is why I haven't used them in a long time, is that they don't actually let you do or let you take advantage of multiple processors. You can't do true parallelism.
> But as soon as you've got one of these coroutine-based languages and you try to exploit multiple processors, if you're doing a lot of coroutine-type operations and you don't have enough processors, you're just saturating one processor.
The other debate is on how parallelism (and concurrency) should be done. Shared-nothing or shared-memory? It'd be foolish to say that only one of them is parallelism, but it would be reasonable to debate the merits of each approach in different systems and circumstances.
Obviously it should be "shared nothing" as it would allow you to horizontally scale your application and code will be much easier to develop and test. But in reality you inevitably need to have a shared state in one way or another. You could try to move that state into some dedicated service, like database, but it's not always performant enough (or even applicable). So you end up with shared memory because of performance.
What would you suggest?
"Many lock-free structures offer atomic-free read paths, notably concurrent containers in garbage collected languages, such as ConcurrentHashMap in Java. Languages without garbage collection have fewer straightforward options, mostly because safe memory reclamation is a hard problem..." - Travis Downs https://travisdowns.github.io/blog/2020/07/06/concurrency-co...
But it seems there is also some benefit to have a VM in addition to a GC for this joint/atomic parallelism.
E.g., you can look up something like a lock-free linked lists, the first of which were described decades ago. They have an algorithm to delete a node from the list, but what often isn't emphasized is that you can't just free that note by calling `free()` on it, because you don't know if any other readers might happen to have a reference to that node, and thus may access the underlying memory. If you free it, they might access freed memory.
In general, this is a hard problem to solve. You can wait, but how long is long enough?
Garbage collected languages solve this more or less automatically: there is no explicit free() but instead the GC determines when there are no more live objects and frees it for you.
This isn't unsolvable in native languages, but none of the solutions are as clean and tradeoff-free as you'd find in a GC'd language.