Unbounded lifetime on trait definition

The following rust program is valid, which surprises me since lifetime 'i is unconstrained, and I'm wondering what does it mean to add lifetime 'i to trait A even if the lifetime is not used.

trait A<'i> {}
struct B;
impl<'i> A<'i> for B {}

I came across this example by creating this code which compiles

struct Ref<'i> {
    _txt: &'i str,
}

struct Object;

trait Trait<'i> {
    type I;
    fn foo(&self, input: &Self::I);
}

impl<'i> Trait<'i> for Object {
    type I = Ref<'i>;

    fn foo(&self, _input: &Ref<'i>) {}
}

However if I remove the lifetime from Trait it doesn't compile:

struct Ref<'i> {
    _txt: &'i str,
}

struct Object;

trait Trait {
    type I;
    fn foo(&self, input: &Self::I);
}

impl<'i> Trait for Object {
    type I = Ref<'i>;

    fn foo(&self, _input: &Ref<'i>) {}
}

It breaks with the following error:

12 | impl<'i> Trait for Object {
   |      ^^ unconstrained lifetime parameter

Put shortly… in this trait

the type I may depend on the type Self and on the lifetime 'i.

Whereas in this trait

the type I may depend only on the type Self and nothing else.


This is why the implementation

is not allowed. I depends on more than just the type Object: If I asked you “what’s the type I in the implementation of Trait for Object”, the answer “it’s Ref<'i>” would be unsatisfactory, because I didn’t mention any lifetime called “'i”, and I’d rightfully ask “where does this lifetime come from?”

On the other hand

is fine: If I asked you “for any lifetime 'i, what’s the type I in the implementation of Trait<'i> for Object”, the answer “it’s Ref<'i>” would be satisfactory. The type uses a lifetime that I already know, I mentioned it in the question myself.


Oh, but now you could say “wait, you formulated the question differently; you mentioned a lifetime 'i in the question!” Well, let’s try. We will reconsider

and ask the question in the form “for any lifetime 'i, what’s the type I in the implementation of Trait for Object?”, with the answer “it’s Ref<'i>”. The problem here is that, imagine we have two (different) lifetime 'foo and 'bar, this answer would tell us that “the type I in the implementation of Trait for Object” is Ref<'foo>, but also by the same argument, we get that this type is Ref<'bar>. So Ref<'foo> and Ref<'bar> are the same type!? But they aren’t, we chose two different lifetimes. That’s essentially the rationale why “unconstrained lifetime parameters” are forbidden. If they were allowed, we could abuse the type system to convince the compiler that two distinct types are the same even though they shouldn’t be.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.