I've been reading through some of the literature on unique types. Here's where Rust as it stands today fits into the picture, as far as I can tell.

The traditional implementations of unique types (as implemented in N. Minsky's Eiffel* [1], most notably) follow the logic of Wadler [2], in which reads to the unique pointer null out the pointer. In this scenario, whenever you move a unique pointer, the original gets nulled out, and attempts to access it fail at runtime. This is known as a "destructive read".

Because passing around unique pointers is very inconvenient when destructive reading (or copying) is the only option, Eiffel* includes the concept of "dynamic aliases" to unique pointers, which are basically our aliases minus the recently-introduced ability to return them (but including the ability to store aliases in locals). Taking a dynamic alias to a unique pointer inside a shared object causes the unique pointer to be nulled out for the lifetime of the dynamic alias. This means that Eiffel* manages to do without any static analysis to support aliases for soundness beyond this simple check.

In 2000 John Boyland proposed "alias burying" [3] to avoid destructive reads, which is similar in spirit to the current alias analysis pass in rustc (but not implemented using type-based analysis). Alias burying is a static analysis pass very similar to ours: any read of a unique pointer (more generally: any operation that changes the unique pointer) results in invalidation of all its aliases.

Crucially, however, Boyland did not adequately deal with the biggest problem with our current alias analysis: closures that can close over arbitrary state. It is treated only in a footnote:

"The analysis also uses (but here does not check) an annotation on procedures that indicates what variables it may read. **A listing of fields possibly accessed during the execution of the procedure would serve well and would also be easy to check modularly. We would prefer however to use an approach which permitted better information hiding, such as obtained using our object-oriented effects system or Leino's data groups."

Essentially, as I understand it Boyland proposes making the set of variables that a closure closes over part of the *type* of that closure in some way.

As to how this relates to Rust:

(1) Our alias analysis, at least the part that relates to unique pointers, isn't new; it's known as "alias burying" in the literature. Although we implement it using TBAA, which I'm concerned about, this is good! It has precedent in the literature.

(2) Performing alias burying in an intraprocedural way seems fundamentally opposed to information hiding via closures. This is the biggest thing that was making me nervous about alias analysis. It doesn't seem that the research literature has solved this problem, and I don't think we have either. In our alias burying, calling a closure tends to wildly trash aliases, which leads to a lot of confusing error messages and inexpressivity.

(3) I don't think that Boyland's solution is a good one for Rust. It only really works in languages like C++ and Java, I think, since callees can see the set of fields that a method might have access to (i.e. private fields become part of the interface). It'd also make fn types even more complicated.

(4) Because of (2), I'm honestly starting to warm up to destructive reads -- nulling out pointers while they're moved or borrowed via aliases. It is certainly the simplest solution, although it introduces null pointers to Rust for the first time. There is a silver lining though: there's only a small fixed set of operations (aliasing or move, basically) that can produce the null pointer, and we should be able to track the origins of null quite easily in debug builds and produce much error messages than the dreaded NullPointerExceptions. Besides, swapping with a sentinel "in-use" value is likely to be very common for parallelism anyhow (farming out elements of an array to subtasks) - and that's basically a null pointer in all but name.

Thoughts? I expect push-back on (4) :)

Patrick

[1] Minsky N., "Towards alias-free pointers"
[2] Wadler P., "Linear types can change the world!"
[3] Boyland J., "Alias burying: Unique variables without destructive reads"
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to