Reference capabilities make it safe to both pass mutable data between actors and to share immutable data amongst actors. Not only that, they make it safe to do it with no copying, no locks, in fact, no runtime overhead at all.
Passing
For an object to be mutable, we need to be sure that no other actor can read from or write to that object. The three mutable reference capabilities (iso
, trn
, and ref
) all make that guarantee.
But what if we want to pass a mutable object from one actor to another? To do that, we need to be sure that the actor that is sending the mutable object also gives up the ability to both read from and write to that object.
This is exactly what iso
does. It is read and write unique, there can only be one reference at a time that can be used for reading or writing. If you send an iso
object to another actor, you will be giving up the ability to read from or write to that object.
So I should use iso
when I want to pass a mutable object between actors? Yes! If you don’t need to pass it, you can just use ref
instead.
Sharing
If you want to share an object amongst actors, then we have to make one of the following guarantees:
- Either no actor can write to the object, in which case any actor can read from it, or
- Only one actor can write to the object, in which case other actors can neither read from or write to the object.
The first guarantee is exactly what val
does. It is globally immutable, so we know that no actor can ever write to that object. As a result, you can freely send val
objects to other actors, without needing to give up the ability to read from that object.
So I should use val
when I want to share an immutable object amongst actors? Yes! If you don’t need to share it, you can just use ref
instead, or box
if you want it to be immutable.
The second guarantee is what tag
does. Not the part about only one actor writing (that’s guaranteed by any mutable reference capability), but the part about not being able to read from or write to an object. That means you can freely pass tag
objects to other actors, without needing to give up the ability to read from or write to that object.
What’s the point in sending a tag reference to another actor if it can’t then read or write the fields? Because tag
can be used to identify objects and sometimes that’s all you need. Also, if the object is an actor you can call behaviours on it even though you only have a tag
.
So I should use tag
when I want to share the identity of a mutable object amongst actors? Yes! Or, really, the identity of anything, whether it’s mutable, immutable, or even an actor.
Reference capabilities that can’t be sent
You may have noticed we didn’t mention trn
, ref
, or box
as things you can send to other actors. That’s because you can’t do it. They don’t make the guarantees we need in order to be safe.
So when should you use those reference capabilities?
- Use
ref
when you need to be able to change an object over time. On the other hand, if your program wouldn’t be any slower if you used an immutable type instead, you may want to use aval
anyway. - Use
box
when you don’t care whether the object is mutable or immutable. In other words, you want to be able to read it, but you don’t need to write to it or share it with other actors. - Use
trn
when you want to be able to change an object for a while, but you also want to be able to make it globally immutable later.