[Pre-RFC] Box patterns and DerefPure


#1

Probably the largest thing Rust lost when moving from sigil-pointers into library pointers is the ability to pattern-match on them, or (more fundamentally) the borrow-checker’s ability to reason about them.

The direct loss of magic-borrowck-ability is merely slightly annoying, but the loss of pattern-matching is rather problematic when working with library-pointer-based data structures.

The primary reason for this loss is that library Deref can execute arbitrary safe code, including modifying the contents in the middle of a match.

This can be fixed, however:

  • Introduce a unsafe trait DerefPure : Deref {}. Behaviour is undefined if the Deref or DerefMut impl of these types is not strongly pure - i.e. calling it zero, one, or more times must have the same effect and return the same result.
  • If a type implements DerefPure, then it behaves like ~ in old Rust - it can be matched by box patterns, and the borrow checker is aware of subfields of it.

#2

I’d be quite interested in exploring the motivation further:

  • We want to allow borrowck to check on dereferencing matches of arbitrary (Deref-implementing) pointers.
  • On the other hand, the Deref implementation can currently eat laundry.™

So to me it seems we have a continuum of possible Deref implementations:

  • Fully pure – side effects free + idempotent
  • Benign inobservably[1] impure idempotent – benign side effects could include filling a cache
  • Idempotent – may have side effects which however do not interfere with the result of Deref itself. Note: The side effects may include eating laundry™
  • Non-idempotent – will return different data on consecutive calls

Obviously, implementation of the last sort aren’t that useful in actual code. However, requiring purity seems quite strict, so could idempotence be sufficient?

[1] for some value of observability. If we include crypto into the picture, side-channel attacks may observe a lot.


#3

I don’t want a state where things like malloc may or may not get called depending on the optimizer’s mood. On the other hand, LLVM does not preserve side-channel-freedom.


#4

Why not use AsRef for that?