trait SomeTrait {
type AssociatedType<'a>;
}
fn shorten<'short, 'long: 'short, T: SomeTrait>(value: T::AssociatedType<'long>) -> T::AssociatedType<'short> {
value
}
This doesn't compile, because the lifetime parameter of AssociatedType is invariant. Is there some change I can make to the trait definition to make it covariant instead, so the above code compiles? Failing that, can I somehow design a trait with a method that will accept a Self with a long lifetime and return a Self with a shorter one, implement it on all the types in my library, and add it as a trait bound on AssociatedType?
I noticed there wasn't anything in the Rust reference or the book about the variance of lifetime parameters of associated types in traits.
Nothing ergonomic, but you could have shorten as an associated function in the trait (using Self instead of T) which implementors then supply.
I think this would basically come down to something like
// You implement this for some representative of the lifetime parameterized
// type (potentially `Thing<'static>`)
trait Covariant {
type Ty<'a>;
fn shorten<'short, 'long: 'short>(value: Self::Ty<'long>) -> Self::Ty<'short>;
}
trait SomeTrait {
type AssociatedType: Covariant;
// Then you use <Self::AssociatedType>::Ty<'_> instead of
// Self::AssociatedType<'_>
}
I.e. mostly the same idea as above, but moved into its own trait.
A bound on the type constructor itself -- the type which is parameterized by a lifetime -- can't work directly in a generic setting, because Rust does not have generic type constructors.
// Not something you can do in Rust
... where for<'a> Self<'a>: ...
impl<T> ... where for<'a> T<'a>: ...
To date they're invariant in a generic setting, and there's no mechanism to forbid implementing the trait with a concrete type constructor that is invariant or contravariant (so anything besides invariance in a generic setting would be unsound).
I’m working on a crate (variance-family) that would be able to provide such a shorten method… modulo having a bunch of complicated trait bounds to express the idea of covariance.
(Alas it’s not on crates.io yet, working on it in my free time means it moves slowly.)
I think the preferred solution is, unfortunately, to try to avoid needing this in the first place. Not much generic code actually needs to assert covariance AFAICT, the exceptions usually involve unsafe.