What does impl<'a> MyServer<'static> mean?

I was running into this error when compiling code shown in the playground:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:30:32
   |
30 |         let token = self.token.clone();
   |                                ^^^^^
   |
note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
  --> src/main.rs:22:6
   |
22 | impl<'a> MyServer<'a> {
   |      ^^
note: ...so that the types are compatible
  --> src/main.rs:30:32
   |
30 |         let token = self.token.clone();
   |                                ^^^^^
   = note: expected `&TokenHolder<'_>`
              found `&TokenHolder<'a>`
   = note: but, the lifetime must be valid for the static lifetime...

I made the problem go away by changing:

impl<'a> MyServer<'a> {

to

impl<'a> MyServer<'static> {

One of my standard soapbox aphorisms is "There's a big difference between solving a problem and making a problem go away." I would like to understand why this made my error go away and therefore whether or not it is the correct way to solve my problem.

Here's my code (and my first time playing with the playground...)

--wpd

#![allow(dead_code)]


#[derive(Clone)]
struct TokenHolder<'a> {
    i32_ref: &'a i32,
}

impl<'a> TokenHolder<'a> {
    pub fn new() -> TokenHolder<'a> {
        static TOKEN: i32 = 123;

        TokenHolder { i32_ref: &TOKEN }
    }
}

struct MyServer<'a> {
    token: TokenHolder<'a>,
}

// This fails to compile
//impl<'a> MyServer<'a> {
// This works
impl<'a> MyServer<'static> {
    pub fn new() -> MyServer<'a> {
        MyServer { token: TokenHolder::new() }
    }

    pub fn run(&self) {
        let token = self.token.clone();
        some_function(move || home(&token));
    }
}

fn main() {
    let server = MyServer::new();
    server.run();
}

fn home(_token: &TokenHolder) {}

fn some_function<F: 'static>(_: F){}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
    Finished dev [unoptimized + debuginfo] target(s) in 2.91s

Well if you read the error message to the end, it says that:

   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `[closure@src/main.rs:31:23: 31:43]` will meet its required lifetime bounds...
  --> src/main.rs:31:9
   |
31 |         some_function(move || home(&token));
   |         ^^^^^^^^^^^^^
note: ...that is required by this bound
  --> src/main.rs:42:21
   |
42 | fn some_function<F: 'static>(_: F){}
   |                     ^^^^^^^

So the chain of constraints is as follows:

  1. some_function specifies that it takes an F of lifetime 'static.
  2. This means that the closure passed into some_function is of 'static lifetime.
  3. Which (roghly) means that the environment captured by the move closure is valid for 'static lifetime.
  4. But then you have the 'a lifetime bound on TokenHolder.
    So that's why, if you put 'static, it works.
1 Like

As for what impl<'a> MyServer<'static> means, it's an implementation for the one type MyServer<'static> that's generic over 'a. The only time you use 'a is:

    pub fn new() -> MyServer<'a> {
        MyServer { token: TokenHolder::new() }
    }

Which is an associated function. So it's not that different from

impl MyServer<'static> {
    pub fn new<'a>() -> MyServer<'a> {
        MyServer { token: TokenHolder::new() }
    }
}

Either way, probably it wouldn't bite you, but this means you can do

    // You defined `new` to return any `'a`, but under `'static` only
    let _: MyServer<'some_named_lifetime> = MyServer::<'static>::new();

But you can't do

    // Error: `MyServer<'static>` is the only thing implemented
    let _: MyServer<'_> = MyServer::<'some_named_lifetime>::new();

(You probably wouldn't have been bit because you would have just left the lifetimes off and the compiler would have figured it out.)

And there's not really any reason to do things this way in either case, as you could instead

impl MyServer<'static> {
    pub fn new() -> Self {
        MyServer { token: TokenHolder::new() }
    }
}

as because your types are covariant, you'll be able to assign the returned MyServer<'static> to MyServer<'arbitrarily_short> anyway.


But might be what you want either; you may really want to be implementing for 'a like you originally tried, and you just need to figure out how to make that work with the rest of the code. (some_function could perhaps not require 'static or your closure could perhaps hold an owned token.)

1 Like

@RedDocMD, @quinedot, thank you for your replies.
@RedDocMD - you outlined the process I followed to finally decide to try changing <'a> to <'static> in my code (which was extracted and reduced from a much larger example).
@quinedot - I didn't think about the fact that by saying:

impl<'a> MyServer<'static> {

I was saying "Here is an implementation of the run() method for the 'static lifetime.

So, now I have:

impl MyServer<'static> {
    pub fn run(&self) {
        let token = self.token.clone();
        some_function(move || home(&token));
    }
}

and I'm still left wondering... what does this mean? token does not have a static lifetime... it gets dropped at the end of run(). Am I lying to the compiler? In this case, I do know that the lifetime of token will outlive the lifetime of the closure... but what happens if some_function() is more complicated (with Send + Sync and friends) and passes its argument of to some other thread? Is this going to cause a problem?

It does not. Instead, it is moved into the closure, and, since the closure doesn't consume the token on call (it only uses a reference), is dropped when the closure is dropped.

2 Likes

@Cerber-Ursi - you're absolutely right! I missed that. Someday, Rust ownership will come naturally to me... that's why I keep practicing :slight_smile:

I still don't grok why using this:

impl<'a> MyServer<'a> {
    pub fn run(&self) {
        let token = self.token.clone();
        some_function(move || home(&token));
    }
}

produces the following error:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:31:32
   |
31 |         let token = self.token.clone();
   |                                ^^^^^
   |
note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
  --> src/main.rs:27:6
   |
27 | impl<'a> MyServer<'a> {
   |      ^^
note: ...so that the types are compatible
  --> src/main.rs:31:32
   |
31 |         let token = self.token.clone();
   |                                ^^^^^
   = note: expected `&TokenHolder<'_>`
              found `&TokenHolder<'a>`
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `[closure@src/main.rs:32:23: 32:43]` will meet its required lifetime bounds...
  --> src/main.rs:32:9
   |
32 |         some_function(move || home(&token));
   |         ^^^^^^^^^^^^^
note: ...that is required by this bound
  --> src/main.rs:43:21
   |
43 | fn some_function<F: 'static>(_: F){}
   |                     ^^^^^^^

For more information about this error, try `rustc --explain E0495`.

but using this:

impl MyServer<'static> {
    pub fn run(&self) {
        let token = self.token.clone();
        some_function(move || home(&token));
    }
}

does not.

Tweaking this code a bit more, I have changed:

impl MyServer<'static> {
    pub fn run(&self) {
        let token = self.token.clone();
        some_function(move || home(&token));
    }
}

to be:

impl MyServer<'static> {
    pub fn run(self) {
        //let token = self.token.clone();
        some_function(move || home(&self.token));
    }
}

(Note that run() now takes ownership of self and therefore I don't need to clone it anymore before using the reference to token into the closure). But my main function still looks like this:

fn main() {
    let server = MyServer::new();
    server.run();
}

I'm trying to understand what I'm saying to the compiler. I feel like:

impl MyServer<'static> {

says "Here is an implementation block that has been specialized to instantiations of MyServer with a relatively infinite lifetime. In this case, since run() takes ownership of self, it actively maintains the (so called) "relatively infinite" lifetime of server declared in main(). That explanation almost starts to make sense to me.

But I still don't understand why:

impl<'a> MyServer<'a> {
    pub fn run(self) {
...

fails to compile... since run() still takes ownership of self. Is this just a case of me being smarter than the compiler? Or is there still more going on?

The lifetime on MyServer corresponds to the lifetime of the token within:

struct MyServer<'ms> { token: TokenHolder<'ms> }

So looking at this we have:

impl<'a> MyServer<'a> {
    pub fn run(&self) {

&self is a &'short Self is a &'short MyServer<'a>.

        let token = self.token.clone();

token is cloned from within MyServer<'a> and is a Token<'a>.

        some_function(move || home(&token));

The Token<'a> gets moved inside of the closure -- it becomes part of the anonymous struct the compiler constructs to be the closure. Let's think of it as Closure<'a>. I've given it a lifetime because it has a Token<'a> within -- the closure can only be valid for 'a. If it were usable anywhere outside of 'a, that would be using a dangling pointer.

Or in trait bound terms, we have Closure<'a>: 'b wherever 'a: 'b ("a is longer than 'b", "'a outlives 'b") -- but we never have Closure<'a>: 'z when 'z: 'a (except when 'z equals 'a itself).

But the signature of some_function is:

fn some_function<F: 'static>(_: F){}

And were are passing it our Closure<'a> in place of the F parameter, so it requires

Closure<'a>: 'static

But 'a is not valid for 'static -- forever -- in the general case, as discussed above. The only way that Closure<'a>: 'static could be satisified is if 'a equals 'static itself.


The only thing that has changed here:

impl MyServer<'static> {
    pub fn run(self) {
        //let token = self.token.clone();
        some_function(move || home(&self.token));
    }
}

Is that instead of cloning the token within and leaving ownership of self with the caller of run, you are now consuming self and moving the token that was within into the closure instead. But when you do this with a MyServer<'a>, you're still moving the Token<'a> within and getting a Closure<'a> as a result.

If you had a MyServer<'a> that contained, or could create, a Token<'static>, then you could get it to work with MyServer<'a>.

1 Like

@quinedot - Thank you. That makes sense to me now. I'm not sure how many more times it will take for me to read it (and to re-read Common Rust Lifetime Misconceptions) before this becomes second nature to me, but your explanation makes sense.

I was particularly concerned about misconception #5 at the site listed above: "if it compiles then my lifetime annotations are correct". Your explanation has alleviated that concern for me.

I thought I had this all figured out, but then I drove home. I do some of my best thinking on my commutes to and from work...
Going back to my earlier example:

impl<'a> MyServer<'a> {
    pub fn run(&self) {
        let token = self.token.clone();
        some_function(move || home(&token));
    }
}

which produces this error:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:35:32
   |
35 |         let token = self.token.clone();
   |                                ^^^^^
   |
note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
  --> src/main.rs:31:6
   |
31 | impl<'a> MyServer<'a> {
   |      ^^
note: ...so that the types are compatible
  --> src/main.rs:35:32
   |
35 |         let token = self.token.clone();
   |                                ^^^^^
   = note: expected `&TokenHolder<'_>`
              found `&TokenHolder<'a>`

Why doesn't clone()ing token work? Shouldn't that produce a new copy of self.token? Shouldn't the lifetime of that cloned copy be independent of the original token?

Yes and yes.

No. Well, it's independent in the sense that it doesn't have to be exactly equal -- it could be shorter. But it can't be any longer (so it can't go from non-'static to 'static).

Token<'_> has a lifetime because it's holding onto a reference. It doesn't own the data it's pointing to, and it has only borrowed it for said lifetime. Bad things will happen if you try to observe the data outside of this lifetime (maybe a data race, maybe a use-after-free because the backing data has been deallocated, things like that). So safe Rust refuses to let you do it (by enforcing lifetimes).

When you clone the Token<'a>, you get another Token<'a> back out -- another reference to the same borrowed data. You didn't clone the backing data. It's still only borrowed for the same amount of time and bad things will still happen if you try to use the reference beyond that the lifetime.

This may seem silly with the particular example (a borrow of an integer), but the rules are the same for all references. Consider if Token contained a reference to a Vec<String> instead.


There's a good chance you're going to end wanting Token to be lifetime-less (always 'static) so that it ends up owning it's data, or perhaps using some sort of shared ownership like an Rc<i32> or something instead of a reference. The examples in this thread are minimal enough that it's hard to advise on the best design though.

Thank you again @quinedot. That makes sense.
Thank you also for your thoughts regarding the design... the design isn't mine, it is extracted from a project I am building that uses the handlebars and rouille crates. I ran into this issue while using that crate and constructed an example mimicking what I saw there.
Thanks again for all of the help.

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.