How to represent invariance - code example

Hey, I'm going through subtyping and variance topic and I've got covariance and contravariance examples working, but I'm struggling to create a simple invariance example that actually fails to compile with the right error.

Here's what I have for the other two:

1. Covariance β€” A type with a longer lifetime can be used where a shorter one is expected.

fn take_short<'short>(_x: &'short str) {}

fn main() {
    let long: &'static str = "hello";
    take_short(long); // &'static β†’ &'short (covariant)
}

References are covariant in their lifetime β€” you can β€œshrink” lifetimes when passing them.

2. Contravariance β€” Function parameter lifetimes flip direction.

fn call_with_static(f: fn(&'static str)) {
    f("hi");
}

fn accepts_any<'a>(_: &'a str) {} // shorter lifetime parameter

fn main() {
    call_with_static(accepts_any); // fn(&str) works as fn(&'static str)
}

What about invariance? Could you help me with some simple example which fails with correct error?

Invariance means that even if you know 'a: 'b, you can't make any assertion about T<'a>: T<'b>. For example, in the following code:

use std::cell::Cell;

fn convert<'a>(input: Cell<&'static str>) -> Cell<&'a str> {
    input
}

We'll get the error:

error: lifetime may not live long enough
 --> src/main.rs:4:5
  |
3 | fn convert<'a>(input: Cell<&'static str>) -> Cell<&'a str> {
  |            -- lifetime `'a` defined here
4 |     input
  |     ^^^^^ returning this value requires that `'a` must outlive `'static`
  |
  = note: requirement occurs because of the type `Cell<&str>`, which makes the generic argument `&str` invariant
  = note: the struct `Cell<T>` is invariant over the parameter `T`
  = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
2 Likes

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.