[Concurrency] Actors & actor isolation

It is not the primary use case, it is one of the applications/implications of @actorIndependent though, it is to address what you have raised as a concern in the overall roadmap thread:

Thus, @actorIndependent and it's friend @actorIndependent(unsafe) exist to address this concern and allow developers to step out of the rigid rules and use external synchronization whenever necessary.

As such, the @actorIndependent is the weaker form of this, and one might even say the less "intended use" one -- though both make sense really.

As for the typesystem aspects of it, I'll leave it up to Doug or John to comment more.

We did talk about allowing an @instantaneous hint for async functions which would not force the "await" on call sites -- this shows up a lot with the Task APIs where we just have them async because they must be called from an async context, not because they'll ever suspend -- but the conformance to sync protocols is a very different beast, it is not instantaneous; rather, it is either unsafe ("break through the model", i.e. @actorIndependent(unsafe)) or known to be safe for some reason @actorIndependent(unsafe) which yeah, just touching "thread safe state" is -- and how we define that indeed it an open hole in the model which is waiting for the "2.0"...

Personally I'd very much like a ValueSemantics protocol, it would have solved many issues, but not all of them. Again, I'll leave it to the compiler folks to argue about the viability of one model over the other though.

Trying to stick to well defined terms only; we don't have "Actor handles", I'll assume you mean a "reference to an actor".

I guess there might have to be some helpers, but coming from other implementations there really isn't all that much an actor reference needs to do – they need to provide equality (potentially serialization of references if we'd like to jump ahead a little bit) but that's about it.

We are not modeling parent/child actor hierarchies in the core model (it can be built on top), nor are we enforcing naming schemes or "props"/"settings" of actors (the "configure an actor" really being handled by overriding pieces of the Actor protocol rather than any new types to do this).

In other runtimes this is fairly logical and well understood and we should follow the same precedent imho. The current shape of the APIs makes it non obvious though because the thinking that it's "just a class" (it isn't just that, imho) clouds the perception.

Having an actor reference means that we point at some actor, somewhere, maybe it's not even on the same node, that's where the actor model actually shines, allowing modeling and understanding of distribution using the same mental model as any other communication.

As such, equality of "actors" is never the same as equality of classes or structs, or anything you "actually really have in your hands", but it really means comparing actor addresses (in a high level meaning, not pointers/addresses). Equality of actor references is then simple: does it point to the same actor or not. Perhaps it is a remote actor, yet it is possible to uniquely identify it. And such equality on actor references is tremendously useful – consider "I have a set of actors I take care of, i get notified to let one of them go away" so I need to remove it from my observed set, thus we need equality of actors in that meaning.

I'm jumping ahead here a little bit, but equality of actors makes a lot of sense and is defined exactly like this in all other runtimes I'm aware of (Akka (actor ref equality), Erlang (PID equality), and Orleans (via grain identifier equality)).

In other runtimes it is more explicit, because we talk about ActorRef<Behavior> or Grain<Behavior> or just PID rather than say "it's just like a class", which brings me to:

It may be counter productive to call them actor class in my opinion, it keeps muddying the water rather than helping clarify one's understanding that they're different beasts once one really gets to use them.

The similarities end at being "a reference rather than a value", however the semantic capabilities the two expose are very different. Beginning from what one can call on them, how they execute, and where they even are located (i.e. not necessarily in the same memory space).

They also cannot inherit from non-actors; so an actor cannot inherit from a class (it could easily violate the substitution principle and allow incorrect synchronous calls to an actor), so they really aren't all that much like classes after all, very similar, but different enough.

This is yet another reason to move towards spelling actors as actor rather than actor class, because the similarities dwindle quite quickly the more one leans into the real world usage of them and restrictions they impose. Also, actors cannot extend classes, but they could ex

I'm not so sure about usefully defining / guaranteeing === it "depends" really where the actor lives. I don't think it is valuable to === actor references other than for the odd trick to avoid a "full" ==.

6 Likes