This isn't quite right. The key thing is that Pony uses the actor model, where an "actor" is an object, a green thread, and an MPSC queue, all bundled together into a single conceptual unit. These MPSC queues are the only synchronization primitive; there aren't mutexes (which means that Pony programs can't internally deadlock, though they can livelock). For this reason, for any given reference (pointer) to a piece of data, you can have any two of mutation, aliasing, and concurrency (i.e., sending the reference to another actor's queue, which doesn't count as mutating the actor). But you can't have all three, because that would allow data races.
Consequently, three "reference capabilities" fall out of this design:
- "iso": allows mutation and concurrency, but not aliasing.
- "val": allows aliasing and concurrency, but not mutation.
- "ref": allows mutation and aliasing, but not concurrency.
The other three are more for generic kinds of programming or to facilitate more complicated tricks:
- "box": only allows aliasing, without mutation or concurrency. Subtype of both val and ref.
- "trn": allows mutation and aliasing, but the aliases are box and so don't themselves allow mutation. Also, you can subsequently change it to either ref or val, to get either mutable aliasing or concurrency (but not both).
- "tag": allows aliasing and concurrency, but not mutation, and (unlike any of the others) also doesn't allow reading the data. The only things you can do are pointer comparisons, and sending something to the referent's queue if the referent is an actor (again, this doesn't count as mutating the actor). Subtype of all the other ones; they all allow tag aliases even if they don't otherwise allow aliasing.