Minimal support for self-referential structures?

The web (and this forum) are full of questions and discussions related to the difficulty to create self-referential structs in Rust. There are crates to ease such creations, but seem to all predate the stabilisation of Pin and do not seem to be very actively maintained.

So my question is whether there is a plan to add minimal support for self-referential structures using Pin in the near future. I imagine a world where this would be valid Rust code:

struct S<'l> {
    value: u32,
    value_ref: RefCell<Option<&'l u32>>,
    _pin: PhantomPinned
}
impl<'l> S<'l> {
    fn do_something(&'l self) {
        *self.value_ref.borrow_mut() = Some(&self.value);
    }
}
fn create_s<'l>() -> Pin<Box<S<'l>>> {
    let s = Box::pin(S {
        value: 1,
        value_ref: RefCell::new(None),
        _pin: PhantomPinned
    });
    s.do_something();
    s
}

Currently, the line s.do_something(); creates a borrow that prevents the move of s at the next line. However, I can imagine there might a way for the compiler to reason that, as the instance of S referred by s will never ever move, calling that s.do_something(); is valid.

Should the compiler accept that, we could very easily create trees and graphs without unsafe code, just using one of the many arena crates (such as bumpalo). Currently, that only works if the reference to the self-referential structure is never moved. This constrains a lot the architectural design of an application, not mentioning libraries.

I think you have a fundamental misconception, and that's that 'l is a valid lifetime for the reference in value_ref, but that's wrong, there's no such lifetime, 'l will always be allowed to live longer than S<'l>, thus allowing to use the reference in value_ref after the value returned by create_s has been dropped. For example given that interface for S<'l> this has to and will compile:

fn main() {
    let static_u32: &'static u32;
    {
        let s = create_s();
        static_u32 = s.value_ref.borrow().unwrap();
    }
    println!("{}", static_u32); // Oh no
}

Thus the compiler is right in giving you an error inside create_s because there's no valid self-referential S<'l> that you can return from that function.

3 Likes

on the topic of support for self-referential structures...here's a relevant recent RFC: