Struct w/ Weak ref to Self

pub struct Foo {
  some fields ... ;
  weak: Weak<Foo>;
}

impl Foo() {
  pub fn new() -> Rc<Foo> {
  //
  }
}

The invariant is that

x: Rc<Foo>; // will always satisfy
Rc::upgrade(x.weak) points to the same object as x

Is this possible? If so, how do we implement the fn new() above ?

You can make its methods to take self: &Rc<Self> instead of &self and Rc::downgrade(self) to get new weak ref.

I'm not sure I understand your proposal properly. To me, the difficulty is:

x = Foo::new();
y = Rc::new(x);
x.weak now needs to refer to Rc::downgrade(y)

due to this cycle, it is not obvious to me how pub fn new() -> Rc<Foo> can be implemented

In particular, I think a solution to this will likely need to separate malloc and init

I think this is exactly what the new (unstable) Rc::new_cyclic is for. There's an example on the similar Arc::new_cyclic.

2 Likes

I mean, why do you want to store the weak ref where you can create it from self for free?

2 Likes

I don't understand what you are proposing. Are you proposing a solution to fn new() -> Rc<Foo> (if so, can you please show sample code). Or are you asking "Why do you want a fn new() -> Rc<Foo> ?

Weak<Self> to the self is only relevant only if the self is stored in some Rc, and you should manage this invariant by your hand. Instead, you can refactor method which touches the weak_ref_to_self field into the method which takes self: &Rc<Self> and clone it.

2 Likes

I need to use Weak<Self> in

impl Drop for Foo {
...
}

It is not clear to me how to do the replacement here.

What kind of data structure are you dealing with, where it makes sense to store a pointer to itself? I couldn't even find a justification for (Rc/Arc)::new_cyclic in the issue, that added it other than "C++ has it, too", which to me is usually an argument against adding something to Rust.

3 Likes

new_cyclic is required to build a fixed structure with parent references without interior mutability; it’s a relatively niche use case. For example:

struct Whole {
    a: Part,
    b: Part
}

struct Part {
    parent: Weak<Whole>,
    data: usize,
}

fn new_whole(a:usize, b:usize)->Rc<Whole> {
    Rc::new_cyclic(|root| Whole {
        a: Part { parent: root.clone(), data: a },
        b: Part { parent: root.clone(), data: b },
    })
}
3 Likes

There are other objects using Weak<Foo> as a 'key'. When the strong count of Rc<Foo> drops to 0, in te drop handler, I want it to notify (via callback handlers) that it is safe to remove resources associated with this Weak<Foo>.