Skip to content

Instantly share code, notes, and snippets.

@ttsiodras
Last active September 8, 2020 08:17
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ttsiodras/e59c5ea4090a11f69073dcc10809d647 to your computer and use it in GitHub Desktop.
Save ttsiodras/e59c5ea4090a11f69073dcc10809d647 to your computer and use it in GitHub Desktop.
Rusty thoughts on affine types

Below is my understanding of affine types and how they help us in Rust (unsure if I got this right - please correct if I am talking nonsense).

The issue is... How can we use the power of a type system so a compiler will block us from doing this wrong sequence of calls?

FILE *fp = NULL;
fclose(fp);
fp = fopen("...");

An idea is to "mirror" the states that the file variable goes through (unused/closed, opened) in the type system:

class FileUnusedOrClosed {
    FileOpened open(...);
}
class FileOpened {
    FileUnusedOrClosed close();
}
FileUnusedOrClosed f;
...
FileOpened o = f.open("...");
f = o.close();

If we try to do it in the wrong sequence, the non-affine-types kind of languages (C++, Java, etC) will catch us: open only exists in FileUnusedOrClosed, and close only exists in FileOpened.

BUT - they won't catch this:

FileOpened o = f.open("...");
FileOpened q = f.open("...");

This is where affine types help - Highlander style: THERE CAN BE ONLY ONE OWNER.

After the assignment to o, f becomes "invalidated" - the compiler knows that you can't reuse it, so the second line is caught... at compile time.

This pattern applies to many state machines (allocating/releasing memory, open/closing files-sockets, etc). Basically, whenever methods (like open above) must automatically move you to a new state, this pattern applies.

UPDATE: A nice comment from /r/glaebhoerl: This becomes even clearer in this "use after free":

void example() {
    FileUnusedOrClosed f;
    FileOpened o = f.open("...");
    f = o.close();
    o.write("oops");
}

Can your language catch that last invalid write - at compile-time? The call to o.close() makes o lose ownership, so the compiler will tell you that o.write is not allowed.

Discussion in Reddit/Rust:

https://www.reddit.com/r/rust/comments/4mdgux/rust_and_affine_types_did_i_get_it_right/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment