Shared leases

⚠️ DADA DOESN'T REALLY EXIST. ⚠️

See the main page for more information. Also, you have to pretend that all the code examples are editable and runnable, with live IDE tooltips and so forth. =)

Earlier, we saw that:

  • You can use the share keyword to convert unique ownership into joint ownership.
  • You can use the lease keyword to temporarily lend out access to a variable without giving up ownership.

But what if you wanted to give many people access to the same object, but only for a limited time? You might want this, for example, so that you could mutate the object again. The answer is that you can combine sharing and leasing to create a shared lease:

class Point(x, y)

async fn main() {
    p = Point(x: 22, y: 44)
    q = p.lease.share
    r = q
    print("p is ({p.x}, {p.y})").await
    print("q is ({q.x}, {q.y})").await
    print("r is ({r.x}, {r.y})").await
    p.x += 1
}

Let's take it step by step. First, position your cursor after p.lease (but before .share) and you will see:

┌───┐
│   │                  ┌───────┐
│ p ├╌my╌╌╌╌╌╌╌╌╌╌╌╌╌╌►│ Point │
│   │                  │ ───── │
│ q ├─leased(p)───────►│ x: 22 │
│   │                  │ y: 44 │
└───┘                  └───────┘

Just after the lease, we have that q is leased from p, the owner. Move the cursor after the .share and we see that the exclusive lease is now a shared lease, indicated by our leased(p):

┌───┐
│   │                  ┌───────┐
│ p ├╌my╌╌╌╌╌╌╌╌╌╌╌╌╌╌►│ Point │
│   │                  │ ───── │
│ q ├─our leased(p)───►│ x: 22 │
│   │                  │ y: 44 │
└───┘                  └───────┘

Although the lease is now shared, p remains the owner of the point (and the lessor of the lease).

Next go past the r = q.share line. As always, sharing a shared thing simply reproduces it:

┌───┐
│   │                  
│ p ├╌my╌╌╌╌╌╌╌╌╌╌╌╌╌╌►┌───────┐
│   │                  │ Point │
│ q ├─our leased(p)───►│ ───── │
│   │                  │ x: 22 │
│ r ├─our leased(p)───►│ y: 44 │
│   │                  └───────┘
└───┘                  

Finally, if you move your cursor to after p.x += 1 you will see that the lease has expired, so q and r have no value:

┌───┐
│   │                  ┌───────┐
│ p ├─my──────────────►│ Point │
│   │                  │ ───── │
│ q │                  │ x: 23 │
│   │                  │ y: 44 │
│ r │                  └───────┘
│   │                  
└───┘                  

Leasing a shared value

If x.lease.share produces a shared lease, what do you think happens with x.share.lease? In other words, what happens if we try to lease a shared value?

class Point(x, y)

async fn main() {
    p = Point(x: 22, y: 44).share
    q = q.lease
}

The answer is that p remains the joint owner of the point, but q has a shared lease:

┌───┐
│   │                  ┌───────┐
│ p ├╌our╌╌╌╌╌╌╌╌╌╌╌╌╌►│ Point │
│   │                  │ ───── │
│ q ├─our leased(p)───►│ x: 22 │
│   │                  │ y: 44 │
└───┘                  └───────┘

There is one interesting wrinkle here. Ordinarily, if you lease an object, then the lease is cancelled when the original object is used again. But if you have a shared lease, it's ok to continue using the original object, since the only thing that both of you can do is to read from it:

class Point(x, y)

async fn main() {
    p = Point(x: 22, y: 44).share
    q = q.lease

    # Reading from `p` does not cancel the lease `q`
    print(p).await

    # Reading from `q` still works:
    print(q).await
}

# Prints:
#
# our Point(22, 44)
# our leased Point(22, 44)