I brought the markdown viewer to you!
Alternative resources:
Subtyping is when one type (like
```
class Animal {}
class Cat inherits Animal {}
fn walk (animal : Animal );
// a Cat can walk!
walk (new Cat ())
```
In type theory "is a subtype of" is represented with the sigil <: so . This is called a subtyping relationship.
Type variance tells us what to do when a type is placed in a bigger type.
Can a
We say if . With covariance, the subtyping relationship "passes through".
We say if . With contravariance, the subtyping relationship is inverted.
Well, imaginary reader, read on.
We turn a &
```
'local : {
let foo : &'static str = "";
let bar : &'local str = foo ;
// bar needs to live for at least this scope
}
```
When assigning
```
let bar : &'local str = foo ;
```
A naive borrow checker would see that and refuse to compile.
But this is valid code! We'd like the borrow checker to realize that a & can fit in places where a & is required.
When a lifetime can shrink to fit.
```
let foo : &'static str = "";
let bar : &'local str = foo ;
```
Because
A &&.
We assume implies &, which happens to be true for &
When a lifetime cannot change.
```
let foo : &mut &'static str = &mut "";
let bar : &mut &'local str = foo ;
// Oh no! Setting a 'static str to a 'local str!
*bar = &String ::new ();
```
When using &
When assigning
```
let bar : &mut &'local str = foo ;
```
& is invariant over &. The type of & is not allowed to become a &, and the compiler successfully rejects the code.
&
&
&
&
Is the following code valid Rust?
```
let foo : &mut &'static str = &mut ... ;
let bar : &mut &'local str = &mut ... ;
*bar = *foo ;
```
For this to be valid, either *
When
When a lifetime can grow to fit.
The opposite of covariance. Only ever used in function parameters.
```
let bar : fn (x : &'local str ) = |_| {};
let foo : fn (x : &'static str ) = bar ;
```
If
Variance follows multiplication rules, where covariance = 1, invariance = 0, and contravariance = -1. Lets see some examples.
In &
In -1 * -1 = 1, two negatives make a positive, so
In &
To find the variance of a struct. We need to look at its fields.
If all the fields are covariant it is covariant.
```
// MyStruct<'a> is covariant over 'a
struct MyStruct <'a > {
x : &'a str , // covariant over 'a
y : &'a bool , // covariant over 'a
}
let foo : MyStruct <'local > = MyStruct <'static > { ... };
```
If all the fields are contravariant it is contravariant.
```
// MyStruct<'a> is contravariant over 'a
struct MyStruct <'a > {
x : fn (&'a str ), // contravariant over 'a
y : fn (&'a bool ), // contravariant over 'a
}
let foo : MyStruct <'static > = MyStruct <'local > { ... };
```
If any field is invariant it is invariant.
```
// MyStruct<'a> is invariant over 'a
struct MyStruct <'a > {
x : *mut &'a str , // invariant over 'a
y : &'a bool , // covariant over 'a
z : fn (&'a u32 ), // contravariant over 'a
}
let foo : MyStruct <'local > = MyStruct <'local > { ... };
```
If the fields have conflicting variance it is invariant.
```
// MyStruct<'a> is invariant over 'a
struct MyStruct <'a > {
x : &'a str , // covariant over 'a
y : fn (&'a str ), // contravariant over 'a
}
let foo : MyStruct <'local > = MyStruct <'local > { ... };
```
This is because covariance requires and contravariance requires which can only be satisfied by invariance.
I've only ever seen this in
If we have the type
```
type F <'a > = fn (&'a ()) -> &'a ()
```
The contravariant function argument requires that .
The covariant return type -> & requires that .
Both requirements and combine to make invariant over .
In the source code for
```
struct Context <'a > {
...
_marker : PhantomData <fn (&'a ()) -> &'a ()>,
...
}
```
This makes
This is almost the same as using * to force invariance, because *
```
struct Context <'a > {
...
_marker : PhantomData <*mut &'a ()>,
...
}
```
But *
If you don't know, an auto-trait is a trait that is automatically implemented for every type only if all of their fields also implement that trait, and *
I asked this myself, and found this person asking the same question.
With immutable references, we accept lifetimes bigger than the one we asked for.
```
// I asked for a 'local but a 'static will do
let x : &'local str = "" as &'static str ;
```
With mutable references, it seems ok to do this.
```
let short : &mut &'local str = &mut &String ::new ();
// contravariance allows growing lifetime
let long : &mut &'static str = short ;
// why not?
*long = "" as &'static str ;
```
But &
```
let short : &mut &'local str = &mut &String ::new ();
let long : &mut &'static str = short ;
// uh oh! turn a 'local into a 'static
let oops : &'static str = *long ;
```
&
&
It must be invariant.
Mutability is generally invariant, this includes UnsafeCell and friends.