Inherited mutability is not an unnecessary restriction from the point of view of memory safety. It's critical to Rust's ability to prevent iterator invalidation and related bugs at compile time. The fact that C++ doesn't do it is the source of many of its memory safety problems, such as dangling references and iterator invalidation.
I had to look this acronym up. In case anybody else needs a definition:
If you're a C++ programmer and don't know about POD types (data types with zero implicit C++ behaviors), you should brush up on your fundamentals – it's essential to understand when and why C++ behaviors (i.e. behaviors above and beyond plain C) are invoked implicitly.
let x = 5
let mut y = &x
If I understood correctly, x is immutable, but can still be mutated via (*y)?I believe it actually means that y can be made to reference something other than x.
let x = 5
let mut y = &x
let i = 13
y = &i
This is similar to C++'s const-pointers and pointers-to-consts, where either a pointer cannot be made to point at something different or the pointer cannot be used to change what it points at. let y = &mut x;
which will result in an error due to x not being mutable. fn main() {
let mut x = ~5;
*x = *x + 1;
println!("{:d}", *x);
}
Or did you mean something else?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.
What advantages does (2) provide? Isn't it a potential source of errors?
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>>,
}