|
|
|
|
|
by millstone
2617 days ago
|
|
The performance cost of interior mutability is often small. IMO the real cost is the undesirable safety properties. For example consider an API like JS's getElementById(). In Rust, if a caller frame has a reference to the same element, this would just panic. It's impossible to statically enforce that no caller can have a reference to this element, and it's unreasonable to require it at runtime. So you either give up safety guarantees (viable, e.g. gtk-rs, but it leaves Rust anemic) or you give up the entire programming model (maybe viable, still a research project). |
|
The most straightforward way to get it working would be to return a `&Element` (or `Rc<Element>` if you like), and make all of `Element`'s fields `Cell`s. No panics, no runtime checks, and you can do everything JS can do. The cost is "infecting" the type definitions with `Cell<T>` and the usage with `.get`/`.set`, and the loss of what is normally rich pointer aliasing information for the optimizer (but which other languages don't have to begin with).
The reason Rust `&mut` feels so restrictive is that it allows you to change the "shape" of the object, thus invalidating (if they existed) any other references into it- replace an enum value with a new variant, reallocate a `Vec`, overwrite a `Box`, etc. But in other memory-safe languages you can't do any of those things. Instead any "shape changing" is done by allocating a new GC'd value and overwriting a pointer- enums are boxed (or don't allow interior pointers), arrays only contain primitives or pointers, etc.
So I like to think of `&Cell<T>` as a kind of third reference mode, that matches what people expect from other languages. It's not fun to use today, but there are a couple of language additions that could make it much, much nicer:
* First, field projection- given a type `struct S { x: T }` and a value `r: &Cell<S>`, let `r.x: Cell<T>`. This is safe as you can't invalidate `&r.x` by overwriting `r`- but by extension you can't project a reference through a `Cell` into an enum or `Vec` (just like other languages as described above).
* Second, some syntactic sugar for reading and writing. Replace `cell.get()` and `cell.set(x)` with `cell` and `cell = x`. Given that `Cell` has zero overhead (other than the loss of optimizations described above) this shouldn't be an issue.