Issue with trait object lifetime

use std::cell::RefCell;
pub trait TDataInstance<'a>
{
    fn set_parent(&'a mut self,parent:& RefCell<dyn TDataInstance<'a> +'a >);
}


pub struct DataInstanceCore<'a>
{
    pub parent:Option<&'a RefCell<dyn TDataInstance<'a> >>,
}

pub struct StructureDataInstance<'a>
{
    pub instance_core:DataInstanceCore<'a>,
    
}

impl<'a> TDataInstance<'a> for StructureDataInstance<'a>  
{
 
    fn set_parent(&'a mut self,parent:& RefCell< dyn TDataInstance<'a> +'a >)
    {
       
       self.instance_core.parent = Some(parent);
    }
}

fn main()
{
    let parent_instance:StructureDataInstance=StructureDataInstance{
        instance_core:DataInstanceCore{
            parent:Option::None
        },
    };
    let mut child_instance:StructureDataInstance=StructureDataInstance{
        instance_core:DataInstanceCore{
            parent:Option::None
        },
    };
    let parent = RefCell::new(parent_instance);
    child_instance.set_parent(&parent);
   
    
  
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error: lifetime may not live long enough
  --> src/main.rs:25:41
   |
19 | impl<'a> TDataInstance<'a> for StructureDataInstance<'a>  
   |      -- lifetime `'a` defined here
...
25 |        self.instance_core.parent = Some(parent);
   |                                         ^^^^^^ cast requires that `'a` must outlive `'static`

error: lifetime may not live long enough
  --> src/main.rs:25:41
   |
22 |     fn set_parent(&'a mut self,parent:& RefCell< dyn TDataInstance<'a> +'a >)
   |                                       - let's call the lifetime of this reference `'1`
...
25 |        self.instance_core.parent = Some(parent);
   |                                         ^^^^^^ cast requires that `'1` must outlive `'static`

help: replace `'a` with `'static`

error: could not compile `playground` due to 2 previous errors

Hi, i am a new ruster and would like to study Rust, but when I use trait object and get above error, can someone help me with this, thanks.

My main recommendation is that you should remove all of the lifetimes in your program, and whenever you want to use a reference, use an Rc instead.

Other than that, I would say that your code looks like trying to write Java in Rust, but the patterns that work in Java don't necessarily work great in Rust. This kind of code will be cumbersome in Rust, no matter what you do.

5 Likes

Thank you, i am new to Rust and always think in object orianted, hard to adjust.

By the way, do you have any recommendation to start with Rust, any books or materials

There's an official Rust book:

https://doc.rust-lang.org/book/

2 Likes

I agree that you should avoid the lifetimes, and additionally note that a lifetime in a trait header is usually a warning sign. But just to look at some of the errors...

pub struct DataInstanceCore<'a> {
    pub parent: Option<&'a RefCell<dyn TDataInstance<'a>>>,
}
// ...
    fn set_parent(&'a mut self, parent: &RefCell<dyn TDataInstance<'a> + 'a>) {
        self.instance_core.parent = Some(parent);
    }

You can't extend the arbitrarily short lifetime of an anonymous reference (parent) to some specific named lifetime ('a). Note that as a generic parameter, 'a could be 'static; this is why some of the errors say "the lifetime would have to be 'static".

Also, trait object lifetimes have context-sensitive defaults and often that default is 'static, so there's a similar problem: you can't assign a &'a RefCell<dyn TDataInstance<'a> + 'a> to someplace that requires &'a RefCell<dyn TDInstance<'a> /* + 'static */>.

This is what it looks like after lining up all those RefCell lifetimes...


...but it's still not actually something useful. What's going on here is that in the implementation:

impl<'a> TDataInstance<'a> for StructureDataInstance<'a> {
    fn set_parent(&'a mut self, parent: &'a RefCell<dyn TDataInstance<'a> + 'a>) {

&'a mut self is a &'a mut StructureDataInstance<'a>, which means that the StructureDataInstance<'a> is mutably -- i.e. exclusively -- borrowed for the rest of it's valid lifetime. Once you call this method, you can never use the struct again. &'a mut Thing<'a> is a red flag and pretty much never what you want. (It comes up a lot when people try to make self-referential data structures in Rust.)

There's no reason to borrow self for 'a here anyway, so that lifetime can just be removed. (There's still some anonymous lifetime there, but now it's an independent lifetime that can be arbitrarily shorter than 'a.)


I walked through all that as an exercise in understanding lifetime errors and to point out some red flags. In the end we have something that runs, but I'm going to note again that I agree with @alice that the structure of the code so far doesn't look like it's going anywhere idiomatic and a different approach is probably better.

1 Like

That's something I observe insanely often. For some reason newbies tend to imagine that lifetime annotations are some kind of marks with requests to the compiler to keep variables around for this or that period of time.

While in reality it's the exact opposite: lifetime annotations can not change anything in the program at all! They exist not to ask the compiler to do something with lifetimes of various objects, but to prove that your program is already correct, that it's already Okay to go.

And compiler, like a dutiful Sancho Panza is trying to understand your explanations. Like Sancho Panza is always sceptical and is trying to understand how the whole thing is supposed to work so is Rust compiler.

It's not that it doesn't trust you to do the right thing, it just knows that you are prone to forgetting minor details and wants clarifications.

But these clarifications only make sense if your program is already correct!

You can not fix broken program by addition of lifetime marks!

1 Like