 # Nomicon variance question

Hello,
The Nomicon chapter about Layout mentions this about variance:" So a `&Vec<&'static str>` couldn't be used where an `&Vec<&'a str>` was expected"
Why does this code compile?

``````pub struct MyVec<T> {
ptr: *mut T,

}

fn f2(obj:&MyVec<&'static str>) {
f1(obj);
}

fn f1<'a>(obj:&MyVec<&'a str>) {

}
``````

What is a good counterexample where a PhantomData would solve the problem?
Regards
Pent

1 Like

In the body of `f2`, the compiler is free to pick any `'a` for `f1` that makes the whole function compile. So it infers that `'a` must be `'static` because you passed `f1` a `&MyVec<&'static str>`.

Here's a function that only compiles if `MyVec<T>` is covariant in `T`:

``````fn f3<'a>(dest: &mut MyVec<&'a str>, obj: MyVec<&'static str>) {
*dest = obj;
}
``````

The compiler doesn't have any freedom to pick what `'a` is because that will be chosen by the caller. In order for the assignment to work, `MyVec<&'static str>` must be a subtype of `MyVec<&'a str>` for any lifetime `'a`.

5 Likes

This is an excellent explanation (Should go in the book...)

Another way to frame it is the fact that lifetimes are also generics, and just like how the compiler can infer the generic types here:

``````let x = vec![1usize, 2, 3, 4];
fn foo<T>(z: Vec<T>) {}
foo(x);
//Is actually
foo::<usize>(x) {}
``````

We can then see that the following also applies:

``````fn foo<'a>(z: &'a [()]) {}

{ //<-- start of 'a
let x = vec![(), (), ()];
foo(&x);
//Is actually
foo::<'a>(&x);
} //<-- end of 'a

//So:
static FOO: &'static [u8] = &[1, 2, 3, 4];
foo(FOO);
//Is actually
foo::<'static>(FOO);
``````
4 Likes