Associated type with lifetime bound


#1

I’m trying to add lifetime bounds to an associated type but it doesn’t seem to work. Any ideas how to get this to compile?

https://is.gd/ksOYlQ


#2

What I actually wanted to express is something like this, which is currently not possible in Rust (see this):

trait Trait {
    type Associated<'a, 'b>;

    fn method<'a, 'b>(&'a self, name: &'b str) -> Self::Associated<'a, 'b>;
}

struct MyType;

impl Trait for MyType {
    type Associated<'a, 'b> = MyAssociated<'a, 'b>;

    fn method<'a, 'b>(&'a self, name: &'b str) -> Self::Associated<'a, 'b> {
        MyAssociated {
            parent: self,
            name: name,
        }
    }
}

struct MyAssociated<'a, 'b> {
    parent: &'a MyType,
    name: &'b str,
}

#3

So now I’ve found something that compiles but I have no idea why:

trait Trait<'a, 'b> {
    type Associated;//: 'a + 'b;

    fn method(&'a self, name: &'b str) -> Self::Associated;
}

struct MyType;

impl<'a, 'b> Trait<'a, 'b> for MyType {
    type Associated = MyAssociated<'a, 'b>;

    fn method(&'a self, name: &'b str) -> Self::Associated {
        MyAssociated {
            parent: self,
            name: name,
        }
    }
}

struct MyAssociated<'a, 'b> {
    parent: &'a MyType,
    name: &'b str,
}

fn main() {}

I’ve removed the lifetime bounds on the associated type (commented out).
But now, how does the compiler know, that the return value is constrained by those lifetimes? Is this correct behavior?


#4

You can read this RFC for some more context about this: https://github.com/rust-lang/rfcs/pull/1598


#5

I’ve read it through but I’m afraid that I don’t understand it completely.
Especially examples like this: https://github.com/rust-lang/rfcs/pull/1598#issuecomment-215984749
It’s probably relevant but just too convoluted for my poor brain. :slight_smile:


#6

That’s a way to hack this with the current type system; you shouldn’t do something like that. Basically, you can’t do what you want right now, but there’s an RFC to allow it some day.


#7

Well, I have a workaround that compiles (see my 3rd post) but I have no idea why.
That’s why I thought this would be relevant.


#8

Your workaround works and does what you want because its also correct for this particular impl, but it has these two big differences -

First, your trait has lifetime parameters. Any time you want to use it in a bound, you’ll need to provide those parameters. Probably you’ll end up needing to use ‘higher ranked lifetimes’ like T: for<'a, 'b> Trait<'a, 'b>, which is quite gnarly.

Second, you haven’t guaranteed that your associated type has to be tied to those lifetimes. This is also a valid impl of that trait:

struct MyType;

struct MyAssociated;

impl<'a, 'b> Trait<'a, 'b> for MyType {
    type Associated = MyAssociated;

    fn method(&'a self, _: &'b str) -> Self::Associated {
        MyAssociated
    }
}

#9

I’ve recently had the exact same issue: https://www.reddit.com/r/rust/comments/51r1ju/is_this_a_bug_in_the_rust_compiler/

At the moment the only real solution to this is to use HRTB, but unfortunately associated types and HRTB don’t play well together with the constraint solver in Rust, so you get a lot of code that should compile, but doesn’t. I’ve yet to create an issue for it, but I’ll probably create one later today.


#10

That’s my experience too.
Unfortunately, I don’t really know what should compile and what not. It’s just trial and error until I have something that works. Or it doesn’t work and I have to find a different approach.