Skip to content

Proposal for mutable slots

Graydon Hoare edited this page Jan 6, 2012 · 1 revision

A proposal for first-class, mutable, interior slots:

The runtime representation of a slot.<T> is bit-for-bit identical to the runtime representation of a T. This means that a parametric container can be given mutable and immutable variants by instantiating with an immutable element type T and a mutable element type slot.<T>.

Providing first-class support for mutable, interior slots makes it possible to create mutable vectors without having to have two different kinds of vectors. This allows us to write a simple, polymorphic map:

fn map.<T,U>(f : &fn(T) -> U, v : T[]) : U[] {
    ...
}

There is one single implementation of map, and the immutable version will produce an immutable vector, and the mutable version will produce a mutable version.

Similarity to one-element tuples

Slots can be simulated with one-element, mutable tuples or records. But those introduce a lot of syntactic overhead. For example, a vector containing records would have to be assigned to a read from by dereferencing the record element by name; in the case of the tuple, by element 0.

Rvalue contexts

In rvalue contexts, extracting a slot's contents is done automatically. This means you can write:

var v : slot.<int>[] = [slot 1, slot 2, slot 3];
var x : int = v[2];

Lvalue contexts

In lvalue contexts, extracting of a slot's contents is done automatically, but the result is not dereferenced. This way, the slot can be assigned to:

var v : slot.<int>[] = [slot 1, slot 2, slot 3];
v[2] = 42;

Collapsing nested slots

Automatic extraction of slot contents is done deeply, so that if you have a type slot.<slot.<T>> it can be used as a T.

Type checking

Type checking must distinguish between lvalue contexts and rvalue contexts and automatically do the coercion to extract the contents of slots.

Code generation

Since the runtime contents of a slot are vacuous, the type checker does not need to insert any special AST representing the extraction of the slot. In other words, the slot is purely a type-level construct.

Convenience forms

It would be good to have a convenience constructor for mutable vectors, such as Ocaml's syntax:

[| 1, 2, 3 |]

This would be equivalent to:

[ slot 1, slot 2, slot 3 ]

It might also be nice to be able to express mutable vector types with a similar syntax, such as:

int[||]

Finally, we might want to consider some sort of special sigil for a slot type, to make it a little lighter-weight than slot.<T>. For example, !T. We can't use !expr for constructing a slot, but we could still use the slot operator. Alternatively, we might be able to avoid the explicit slot constructor altogether with an additional automatic coercion:

var v : int[!] = [1,2,3,4,5];

However, this would mean that the type of literals could no longer be inferred. So that's probably undesirable. This leaves us with:

var v : int[!] = [!1, 2, 3, 4, 5];

or

var v : int[!] = [| 1, 2, 3, 4, 5 |];

or something like that.

Alternatives considered

We considered having mutability be an attribute of vectors, and possibly an attribute that could be used for custom collection types as well. But then this required some kind of subtyping relationship, where you would write map as a function that accepted a vector with some sort of mutable? attribute. In other words, there was some sort of notion of "mutability polymorphism." This made for much more complicated type signatures for map, and was ad hoc and didn't seem to correspond to familiar concepts from known type systems.

All Categories:

Clone this wiki locally