-
Notifications
You must be signed in to change notification settings - Fork 1
Proposal for mutable slots
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.
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.
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];
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;
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 must distinguish between lvalue contexts and rvalue contexts and automatically do the coercion to extract the contents of slots.
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.
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.
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.