> No I'm thinking of actors - stateful, non-determinstic, racey actors. A minefield of classic concurrency bugs!

Well yes systems of actors contain race conditions. However, so does Rust's or Go's concurrency primitives. The only way to completely avoid race conditions I know of would be formal methods via TLA+ or similar. From my brief looks into TLA+ it'd appear to match actor implementation models pretty well (messages to actors yield new states).

> But the global state of all the actors is shared. If an actor you send a message to responds differently due to its state then let's be honest you're implicitly sharing that state.

It's not really whether a program has state, but how that state is accessed and modified. In the actor model, only an actor itself can modify it's own data which makes it easier to reason about many classes of concurrency problems. Especially actions within an actor itself are deterministic (generally speaking). This makes a lot of problems become very straightforward to model without needing locks everywhere. The concurrency problem is shifted to modeling the behavior of a group of actors, which helps enforce separation of concurrency concerns from the lower level implementation details (with a good framework at least).

Since I was asking and thinking about Ruby getting (preemptive) actors initially, this frame of thought seems odd to me. The entire foundation of Ruby is built on objects that contain implicit state and on those objects behaving differently based on their state even to the point of checking for unhandled "messages" via `#method_missing`.

Th fork/join model can be emulated rather well as @dnautics described in a sibling comment. It's close to the model used in Elixir's Phoenix web server where each request just forks an Erlang process to handle it.

At the end of the day, issues with races in the actor paradigm are little different than communicating with remote programs as either fork'ed processes or network programs. Just fork'ing a program may avoid some concurrency issues by not doing any useful work by itself. If you do use fork/join to service http requests via sockets you're now relying on implicit state from the OS to do the heavy lifting.

If anything Linux's new `io_uring` works by treating a process like an actor where the process & kernel pass messages via a "messsage queue" which means your forks will just be acting as pseudo-actors anyway. Side note, on Linux doing this saves a lot of context switches by not preempting the OS process' call stack via a direct syscall every time it has something to communicate to the kernel. That gives a big speed bump to IO heavy programs. There can be significant performance benefits to making programming models work more like the hardware. I expect that actor models will grow to be a better performance match as core counts continue rising.

> Don't we want something higher level and safer than directly mapping to our hardware?

Certainly! ... if it makes acceptable tradeoff's in other areas. Though Actor's are really more of a base system to build higher level constructs that are easier/safer to use. Most programming shouldn't be done using your own concurrency primitives, but building on well thought out and tested libraries.

Mainly though, the idea of a Ruby with preemptive actors seems fun to me. Perhaps something you could map to lego robot's for kids.