1

The following (contrived) example has the chain method calling the create_future method which retuns a Future. On successful completion of the future, the result of the do_something method is returned.

use futures::Future; //0.1.28

type AnError = Box<std::error::Error>;

pub trait Test {
    fn do_something(&self) -> Result<(), AnError>;
    fn create_future(&self) -> Box<Future<Item = (), Error = AnError>>;
    fn chain(&self) -> Box<Future<Item = (), Error = AnError>> {
        Box::new(
            self.create_future()
                .then(|f| f.and_then(|_| self.do_something())),
        )
    }
}

This does not compile:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/lib.rs:11:23
   |
11 |                 .then(|f| f.and_then(|_| self.do_something())),
   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 8:5...
  --> src/lib.rs:8:5
   |
8  | /     fn chain(&self) -> Box<Future<Item = (), Error = AnError>> {
9  | |         Box::new(
10 | |             self.create_future()
11 | |                 .then(|f| f.and_then(|_| self.do_something())),
12 | |         )
13 | |     }
   | |_____^
   = note: ...so that the types are compatible:
           expected &&Self
              found &&Self
   = note: but, the lifetime must be valid for the static lifetime...
   = note: ...so that the expression is assignable:
           expected std::boxed::Box<(dyn futures::future::Future<Error = std::boxed::Box<(dyn std::error::Error + 'static)>, Item = ()> + 'static)>
              found std::boxed::Box<dyn futures::future::Future<Error = std::boxed::Box<dyn std::error::Error>, Item = ()>>

The problem is the use of self in the self.do_something() call (replace this call by Ok(()) and this example will compile).

The compiler is complaining that the struct instance (self) may be outlived in that future... which seems a bit hard to swallow, since chain has been called on it.

How can I make this work and have the struct instance call itself in a future? I'm using Rust 1.36.


Unless I missed something, the suggested solution in the duplicate (passing a ref as the result of the future) is not enough

use futures::Future; //0.1.28

type AnError = Box<std::error::Error>;

pub trait Test {
    fn do_something(&self) -> Result<(), AnError>;
    fn create_future(&self) -> Box<Future<Item = &Test, Error = AnError>>; //<== CHANGE `Item=()` to `Item=&Test` to return a ref
    fn chain(&self) -> Box<Future<Item = (), Error = AnError>> {
        Box::new(
            self.create_future()
                .then(|f| f.and_then(|t| t.do_something())), // <== CHANGE recovering `t` from the future the ref to `Test`, and calling on it
        )
    }
}

fails with

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/lib.rs:10:18
   |
10 |             self.create_future()
   |                  ^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 8:5...
  --> src/lib.rs:8:5
   |
8  | /     fn chain(&self) -> Box<Future<Item = (), Error = AnError>> {
9  | |         Box::new(
10 | |             self.create_future()
11 | |                 .then(|f| f.and_then(|t| t.do_something())), // <== change there
12 | |         )
13 | |     }
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src/lib.rs:10:13
   |
10 |             self.create_future()
   |             ^^^^
   = note: but, the lifetime must be valid for the static lifetime...
   = note: ...so that the expression is assignable:
           expected std::boxed::Box<(dyn futures::future::Future<Error = std::boxed::Box<(dyn std::error::Error + 'static)>, Item = ()> + 'static)>
              found std::boxed::Box<dyn futures::future::Future<Error = std::boxed::Box<dyn std::error::Error>, Item = ()>>

SOLUTION:

Assign explicit lifetimes to self and the Future. Copied from @Shepmaster (thanks) playground.

type AnError = Box<std::error::Error>;

pub trait Test {
    fn do_something(&self) -> Result<(), AnError>;
    fn create_future(&self) -> Box<Future<Item = &Test, Error = AnError>>;
    fn chain<'a>(&'a self) -> Box<Future<Item = (), Error = AnError> + 'a> {
        Box::new(
            self.create_future()
                .then(|f| f.and_then(|_| self.do_something())),
        )
    }
}
Bruno Grieder
  • 28,128
  • 8
  • 69
  • 101
  • [The duplicates applied](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=fa0102d3144e48d916fbf3934d3f096d). – Shepmaster Jul 10 '19 at 17:16
  • @Shepmaster the solution suggested in the "duplicate" does not seem "good enough". Please see **EDIT** – Bruno Grieder Jul 10 '19 at 19:17
  • What is unclear about [the comment where I applied it to your code](https://stackoverflow.com/questions/56975388/calling-itself-in-a-future#comment100487551_56975388)? Or the [a slightly simpler version](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=69a5e8e44f1a8c36ddbdc9be0cccb5f2) – Shepmaster Jul 10 '19 at 19:23
  • @Shepmaster I annotated the lines I changed in the above code with a comment started with the word 'CHANGE'. These changes do what I understood is suggested in the "duplicate" – Bruno Grieder Jul 10 '19 at 19:32
  • I do not understand where the communication gap is. If you review the [code I've changed for you](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=fa0102d3144e48d916fbf3934d3f096d) and the other [code I've changed for you](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=69a5e8e44f1a8c36ddbdc9be0cccb5f2), and diff them against your original code, you will very quickly see the appropriate changes. From the duplicate: *Note that we assign an explicit lifetime to `self` and use that in the returned value (via + `'a`)* – Shepmaster Jul 10 '19 at 19:35
  • 1
    @Shepmaster Sorry, I likely misunderstood your first reply. Yes the version with the lifetime looks good, is more explicit (and works fine). Thanks – Bruno Grieder Jul 10 '19 at 20:34
  • @Shepmaster Since the final solution involves lifetimes rather than passing a ref as in the duplicate, do you want to post an answer that I can award and remove the duplicate flag ? – Bruno Grieder Jul 10 '19 at 20:39
  • 1
    You are also passing a reference: `&self`. References contain lifetimes; these truly are the same question and answer; duplicating the answer won't make Stack Overflow a better set of content, but thank you! – Shepmaster Jul 10 '19 at 20:41

0 Answers0