Weird behavior with traits and lifetimes

Code: https://play.rust-lang.org/?gist=2d53e66439084b39cc42e2604ec2ce76&version=stable&mode=debug&edition=2015

Why does get_t not compile due to lifetimes, but get_i work. I see that it is inserting a 'static bound to the type parameter, but why?

It’s implied by the trait definition: T: ?Sized there is basically T: ?Sized + 'static since there’s no lifetime parameter on the trait itself. You could define it as trait Trait<'a, T: ?Sized + 'a>, but this doesn’t buy anything here because Item has no lifetime params itself (and is already storing a 'static trait object). Ignore my thinko! Only thing 'static was my brain :slight_smile:

Ok, thanks for the help, that clears it up!

That's not it. Every type parameter on a struct/trait in fact also plays the role of a lifetime parameter. Were this not the case, you'd never be able to work with types like Box<&'a T>.

It just needs more annotations.

trait ObjectSafeTrait {}

trait Trait<T: ?Sized> {
    fn get_t(&self) -> &T;
}

pub struct Item<'a>(Box<dyn ObjectSafeTrait + 'a>);

impl<'a> Trait<dyn ObjectSafeTrait + 'a> for Item<'a> {
    fn get_t(&self) -> &(dyn ObjectSafeTrait + 'a) {
        &*self.0
    }
}
    
impl<'a> Item<'a> {
    fn get_i(&self) -> &(dyn ObjectSafeTrait + 'a) {
        &*self.0
    }
}
2 Likes

Sorry, I should explain:

The main problem was that Item needed a lifetime. Box<dyn ObjectSafeTrait> uses a default lifetime of Box<dyn ObjectSafeTrait + 'static> (what else would it use?)

The others had to be added so that those functions could support Item with arbitrary 'a. In this manner, this lifetime will infect your codebase. (Trait objects with lifetime parameters have a bad tendency of doing that!) If this is in high-level code where performance is not critical, I suggest using owned types like Rc rather than borrows in the implementors of ObjectSafeTrait so that you don’t need to worry about lifetimes.

1 Like

You’re right - I mucked this up! :man_facepalming: