Skip to content
This repository has been archived by the owner on Jun 6, 2021. It is now read-only.

Note: Explicit Immutability

Alex Rønne Petersen edited this page Jun 9, 2013 · 4 revisions

This note is a short explanation of explicit immutability in types.

If a function takes, for example, an array of integers, it's useful to be able to say that the function has no intention of modifying those integers even if it could. For instance, a naive search function could look like:

pub fn find(array : &[int], int item) -> Option[uint] {
    for (i, x) in array {
        if x == item {
            return Some(i);
        };
    };

    None();
}

We could then say:

let arr = @[1, 2, 3];
let idx = extract(find(arr, 2));
assert idx == 1;

But we couldn't say:

let arr = @mut [1, 2, 3];
let idx = extract(find(arr, 2));
assert idx == 1;

The reason we cannot do this is that the type &[int] is strongly immutable; that is, under no circumstances can its contents change, ever. What we would like to express is that find doesn't care about the mutability guarantees and just wants to guarantee that it won't mutate anything, such that it can operate on both strongly immutable arrays and mutable arrays.

Thus, the imm qualifier can be used:

pub fn find(array : &imm [int], int item) -> Option[uint] {
    for (i, x) in array {
        if x == item {
            return Some(i);
        };
    };

    None();
}

Both examples above will now work, because &[int] and &mut [int] both implicitly convert to &imm [int].

More generally, we could write the function like this:

pub fn find[T : Eq](array : &imm [T], T item) -> Option[uint] {
    for (i, x) in array {
        if x == item {
            return Some(i);
        };
    };

    None();
}

Similarly, imm can be used for regular pointers:

pub fn pointer_eq[T](p1 : &imm T, p2 : &imm T) -> bool {
    p1 === p2;
}

We can call this function with various different pointer types:

let p1 = @42;
let p2 = @42;
assert !pointer_eq(p1, p2);

let p1 = @mut 42;
let p2 = @42;
assert !pointer_eq(p1, p2);

let p1 = @mut 42;
let p2 = @mut 42;
assert !pointer_eq(p1, p2);

In short, imm is the bridge connecting immutable and mutable data.

Clone this wiki locally