Capability Subtyping
Subtyping is about substitutability. That is, if we need to supply a certain type, what other types can we substitute instead? Reference capabilities factor into this.
Simple substitution
First, let's cover substitution without worrying about ephemeral types (^) or alias types (!). The <: symbol means "is a subtype of" or alternatively "can be substituted for".
iso <: trn. Anisois read and write unique, and atrnis just write unique, so it's safe to substitute anisofor atrn.trn <: ref. Atrnis mutable and also write unique. Arefis mutable but makes no uniqueness guarantees. It's safe to substitute atrnfor aref.trn <: val. This one is interesting. Atrnis write unique and avalis globally immutable, so why is it safe to substitute atrnfor aval? The key is that, in order to do so, you have to give up thetrnyou have. If you give up the only variable that can write to an object, you know that no variable can write to it. That means it's safe to consider it globally immutable.ref <: box. Arefguarantees no other actor can read from or write to the object. Aboxjust guarantees no other actor can write to the object, so it's safe to substitute areffor abox.val <: box. Avalguarantees no actor, not even this one, can write to the object. Aboxjust guarantees no other actor can write to the object, so it's safe to substitute avalfor abox.box <: tag. Aboxguarantees no other actor can write to the object, and atagmakes no guarantees at all, so it's safe to substitute aboxfor atag.
Subtyping is transitive. That means that since iso <: trn and trn <: ref and ref <: box, we also get iso <: box.
Aliased substitution
Now let's consider what happens when we have an alias of a reference capability. For example, if we have some iso and we alias it (without doing a consume or a destructive read), the type we get is iso!, not iso.
iso! <: tag. This is a pretty big change. Instead of being a subtype of everything likeiso, the only thing aniso!is a subtype of istag. This is because theisostill exists, and is still read and write unique. Any alias can neither read from nor write to the object. That means aniso!can only be a subtype oftag.trn! <: box. This is a change too, but not as big a change. Sincetrnis only write unique, it's ok for aliases to read from the object, but it's not ok for aliases to write to the object. That means we could haveboxorvalaliases - exceptvalguarantees that no alias can write to the object! Since ourtrnstill exists and can write to the object, avalalias would break the guarantees thatvalmakes. So atrn!can only be a subtype ofbox(and, transitively,tagas well).ref! <: ref. Since arefonly guarantees that other actors can neither read from nor write to the object, it's ok to make morerefaliases within the same actor.val! <: val. Since avalonly guarantees that no actor can write to the object, its ok to make morevalaliases since they can't write to the object either.box! <: box. Aboxonly guarantees that other actors can't write to the object. Bothvalandrefmake that guarantee too, so why canboxonly alias asbox? It's because we can't make more guarantees when we alias something. That meansboxcan only alias asbox.tag! <: tag. Atagdoesn't make any guarantees at all. Just like with abox, we can't make more guarantees when we make a new alias, so atagcan only alias as atag.
Ephemeral substitution
The last case to consider is when we have an ephemeral reference capability. For example, if we have some iso and we consume it or do a destructive read, the type we get is iso^, not iso.
iso^ <: iso. This is pretty simple. When we give aniso^a name, by assigning it to something or passing it as an argument to a method, it loses the^and becomes a plain oldiso. We know we gave up our previousiso, so it's safe to have a new one.trn^ <: trn. This works exactly likeiso^. The guarantee is weaker (write uniqueness instead of read and write uniqueness), but it works the same way.ref^ <: ref^andref^ <: refandref <: ref^. Here, we have another case. Not only is aref^a subtype of aref, it's also a subtype of aref^. What's going on here? The reason is that an ephemeral reference capability is a way of saying "a reference capability that, when aliased, results in the base reference capability". Since arefcan be aliased as aref, that meansrefandref^are completely interchangeable.val^,box^,tag^. These all work the same way asref, that is, they are interchangeable with the base reference capability. It's for the same reason: all of these reference capabilities can be aliased as themselves.
Why do ref^, val^, box^, and tag^ exist if they are interchangeable with their base reference capabilities? It's for two reasons: reference capability recovery and generics. We'll cover both of those later.