5 ms·
He means immutability when he says "const-ness". There are four possibilities for mutability of a single pointer: 1. The pointer is mutable, but its contents a
by ndeine 12y ago
He means immutability when he says "const-ness". There are four possibilities for mutability of a single pointer:
1. The pointer is mutable, but its contents are immutable.
2. The pointer is immutable, but its contents are mutable.
3. The pointer is immutable and the contents are immutable.
4. The pointer is mutable and its contents are mutable.
Right now for owned pointers Rust gives us (3) and (4), but no obvious way to achieve (1) and (2). Although you might argue that the borrowing semantics give us these powers, just not directly with owned pointers - which we shouldn't be using directly if we're asking for that control, we should be lending them out in a well-controlled manner.
- steveklabnik 12y agoAhh, thank you. And yes, that's what I'd argue.
- pcwalton 12y agoYou can use privacy for (1); admittedly it's a little hokey, but I feel it's not worth the added complexity to add field-level immutability directly into the language since you can use other language features to effectively achieve it. `std::cell::Cell` and `std::cell::RefCell` give you (2).
- azth 12y ago> `std::cell::Cell` and `std::cell::RefCell` give you (2). What advantages does (2) provide? Isn't it a potential source of errors?
- pcwalton 12y agoIt is, but sometimes you have to do it for practicality. Usually this comes up when people use `Rc<T>`, as that only supports immutable types (so any mutability you want needs to be in the form of `Cell`/`RefCell`).
- azth 12y agoWould it be better to combine both types (e.g. a MutRc<T> type), and get rid of Cell/RefCell?
- pcwalton 12y agoI don't think so, because then you'd get an overconservative iterator invalidation checker. For example: struct Foo { a: Vec<int>, b: Vec<int>, } let foo = Rc::new(RefCell::new(Foo::new(...))); for x in foo.borrow_mut().a.mut_iter() { for y in foo.borrow_mut().b.mut_iter() { // ^^^ FAILURE: a is already borrowed mutably } } The failure happens because the RefCell is checking to make sure there are no two `&mut` references at the same time to `Foo`, to prevent iterator invalidation. But this is silly, because it only needs to prevent access to `a` while you're iterating over it, not both `a` and `b`. Changing the definition of `Foo` to this fixes the problem: struct Foo { a: RefCell<Vec<int>>, b: RefCell<Vec<int>>, }
- azth 12y agoMakes sense. Though Cells would really stand out in the code as a potential for race conditions (unless you get a run time failure?). Thanks for the insight.
- pcwalton 12y agoThere is a special bound--Share--that is required on thread-safe data structures and forbids Cell/RefCell. The thread-safe equivalents of Cell and RefCell are Atomic and Mutex, respectively.