Dmitry
Dmitry

Reputation: 1637

Additional `'static` requirement in traits associated types?

Consider next function for example:

fn print(input: &dyn Display) {
    println!("{}", input);
}

It works fine, as intended.

Now consider a little bit more complex example using trait with the same function inside:

trait Print {
    type Input: ?Sized;

    fn print(input: &Self::Input);
}

impl Print for f64 {
    type Input = dyn Display;
    
    // actually the same function as before
    fn print(input: &dyn Display) {
        println!("{}", input);
    }
}

Now if I modify first function like this:

fn print(input: &dyn Display) {
    f64::print(input);
}

I got compile error:

error[E0759]: `input` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement

Why is this happening? I see no reason for 'static lifetime requirement in trait's associated type.

Worked example here.

Upvotes: 1

Views: 64

Answers (1)

dumbass
dumbass

Reputation: 27208

Yes, when a dyn _ type is used as an associated type, it implicitly receives a lifetime bound of 'static. This is to prevent situations like this:

pub trait Stew {
    type Item: ?Sized;
    fn stew(&mut self, item: Box<Self::Item>);
}

use std::fmt::Display;

pub struct DisplayStew(Vec<Box<dyn Display>>);

impl Stew for DisplayStew {
    type Item = dyn Display;

    fn stew(&mut self, item: Box<Self::Item>) {
        self.0.push(item);
    }
}

impl DisplayStew {
    pub fn new() -> Self {
        DisplayStew(Vec::new())
    }

    pub fn look(&self) {
        for item in &self.0 {
            println!("- {}", item);
        }
    }
}

fn main() {
    let mut bowl = DisplayStew::new();
    bowl.stew(Box::new(123.456));
    bowl.stew(Box::new("abcdef"));
    { // 'a begins
        let s = "foo".to_owned();
        bowl.stew(Box::new(&s)); // Box<&'a str>
    } // 'a expires
    // s was borrowed by bowl, but has ceased to exist, what now?
    bowl.look();
}

Without a lifetime parameter, the compiler has no way of restricting how long a type may keep a reference to its associated type.

On stable Rust (1.58.1), there is currently no way to address this, but the following version works on unstable:

#![feature(generic_associated_types)]

use std::fmt::Display;

trait Print {
    type Input<'a>: ?Sized;

    fn print<'a>(input: &'a Self::Input<'a>);
}

impl Print for f64 {
    type Input<'a> = dyn Display + 'a;

    fn print<'a>(input: &'a (dyn Display + 'a)) {
        println!("{}", input);
    }
}

fn print(input: &dyn Display) {
    println!("{}", input);
    f64::print(input);
}

fn main() {
    print(&123.);
}

Upvotes: 3

Related Questions