How do you make a trait function return a future with a lifetime?

Hi! I'm trying to make a trait method return a future. The future might need to access member variables, and I can't get it to work.

#![feature(type_alias_impl_trait)]
use std::future::*;

struct Foo(i32);

// Outside of a trait this all works fine
type T<'a> = impl Future<Output=i32> + 'a;
impl Foo {
    async fn ref_async(self: &Self) -> i32 {
        self.0
    }
    // All these variants are ok.
    // fn blah<'a>(self: &'a Self) -> impl Future<Output=i32> + 'a {
    // fn blah<'a>(self: &'a Self) -> T<'a> {
    fn blah(self: &Self) -> T<'_> {
        self.ref_async()
    }
}

But everything goes a bit hairbrained in a trait:

trait SomeTrait {
    type TT;
    fn blah(self: &Self) -> Self::TT;
}

impl SomeTrait for Foo {
    type TT<'a> = impl Future<Output=i32> + 'a;
    fn blah<'a>(self: &'a Self) -> Self::TT<'a> { // <- Errors..
        self.ref_async()
    }
}

(Playground)

I can't seem to figure out how to associate the lifetime of my self object with the return value. Does this need GAT or something?

Yes, you can't express that associated type currently.

The alternative is fn blah<'a>(&'a self) -> Pin<Box<dyn Future<Output = i32> + 'a>> { ... }

Aww! I was hoping to avoid allocations, though I suppose it shouldn't make much difference in practice for what I'm working on. It itches doing it this way knowing allocation-free futures are right around the corner though :smiley:

Thanks for your help!

I don't know if it really applies to your use case, but for a related issue there is the ::async_trait crate, that will automagically Pin<Box<dyn Future>> the return type of the async fns methods of a trait.

I saw that and it looks nice, but seems that it just adds sugar on top of doing what @sfackler said above. It also makes errors in my functions get misattributed to the macro in my IDE, which is pretty bad while I'm learning (when I make mistakes I need all the help I can get).

1 Like