impl TraitX for TraitY
is using TraitY
as a dynamically sized type (DST). If we add the required lifetime bound (see e.g. this for more info about the necessity of the lifetime bound), the compiler will complain in this manner:
trait TraitX { }
trait TraitY { }
impl<'a> TraitX for TraitY+'a { }
fn main() {}
<anon>:3:1: 3:34 error: the trait `core::kinds::Sized` is not implemented for the type `TraitY+'a`
<anon>:3 impl<'a> TraitX for TraitY+'a { }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<anon>:3:1: 3:34 note: the trait `core::kinds::Sized` must be implemented because it is required by `TraitX`
<anon>:3 impl<'a> TraitX for TraitY+'a { }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
playpen
The errors are saying that TraitY+'a
is not sized, that is, it doesn't have a size known at compile time (e.g. u8
has size 1, Vec<T>
is the size of 3 pointers).
The syntax is implementing TraitX
for TraitY
trait objects (these are covered in the "object types" section of the reference), allowing it to be handled (behind a pointer) in places where a value implementing TraitX
is expected. The working usage involves some extra Sized?
annotations, these say that whatever they're attached to is optionally (?
) sized (the default is for things to be assumed to be sized).
#![allow(dead_code)]
// indicate that it's OK to implement this trait for DSTs
trait TraitX for Sized? { }
trait TraitY { }
trait TraitZ { }
impl<'a> TraitX for TraitY+'a { }
// the Sized? is to allow DSTs to be passed to this.
fn example<Sized? T: TraitX>(_: &T) {}
fn call_it(x: &TraitY, _y: &TraitZ) {
example::<TraitY>(x); // only possible if `TraitY` impls `TraitX`.
// error:
// example::<TraitZ>(_y); // `TraitZ` doesn't impl `TraitX`.
}
fn main() {}
playpen
The explicit ::<TraitY>
type hint is required when calling a function with an unsized type for now, but this is a bug #17178. For the moment, there's still quite a few bugs with DST so it's not easy actually to use in practice, but this will improve.
The major motivation for DST is making handling trait objects more consistent with other pointer types, e.g. we currently only support &Trait
and Box<Trait>
trait objects, but DST is designed to allow other pointer types like Rc<Trait>
, Arc<Trait>
. DST also allows treating those like real pointers, e.g. if obj: Box<Trait>
then &*obj
is only now possible with DST, previously it was illegal because trait objects are fat pointers, not normal pointers.