Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I'm not sure what you mean about unique pointers and const-ness. Can you explain? You can make unique pointers mutable:

    fn main() {
        let mut x = ~5;
        *x = *x + 1;
        println!("{:d}", *x);
    }
Or did you mean something else?


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.


You 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).


> `std::cell::Cell` and `std::cell::RefCell` give you (2).

What advantages does (2) provide? Isn't it a potential source of errors?


It 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`).


Would it be better to combine both types (e.g. a MutRc<T> type), and get rid of Cell/RefCell?


I 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>>,
    }


Makes 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.


There 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.


Ahh, thank you. And yes, that's what I'd argue.




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: