Editor's note: This code no longer produces the same error after RFC 599 was implemented, but the concepts discussed in the answers are still valid.
I'm trying to compile this code:
trait A {
fn f(&self);
}
struct S {
a: Box<A>,
}
and I'm getting this error:
a.rs:6:13: 6:14 error: explicit lifetime bound required
a.rs:6 a: Box<A>,
I want S.a to own an instance of A, and don't see how that lifetime is appropriate here. What do I need to do to make the compiler happy?
My Rust version:
rustc --version
rustc 0.12.0-pre-nightly (79a5448f4 2014-09-13 20:36:02 +0000)
(Slightly pedantic point: that A is a trait, so S is not owning an instance of A, it is owning an boxed instance of some type that implements A.)
A trait object represents data with some unknown type, that is, the only thing known about the data is that it implements the trait A. Because the type is not known, the compiler cannot directly reason about the lifetime of the contained data, and so requires that this information is explicitly stated in the trait object type.
This is done via Trait+'lifetime. The easiest route is to just use 'static, that is, completely disallow storing data that can become invalid due to scopes:
a: Box<A + 'static>
Previously, (before the possibility of lifetime-bounded trait objects and this explicit lifetime bound required error message was introduced) all boxed trait objects were implicitly 'static, that is, this restricted form was the only choice.
The most flexible form is exposing the lifetime externally:
struct S<'x> {
a: Box<A + 'x>
}
This allows S to store a trait object of any type that implements A, possibly with some restrictions on the scopes in which the S is valid (i.e. for types for which 'x is less than 'static the S object will be trapped within some stack frame).
The problem here is that a trait can be implemented for references too, so if you don't specify the required lifetime for Box anything could be stored in there.
You can see about lifetime requirements in this rfc.
So one possible solution is to bind the lifetime so Send (we put I in S):
trait A {
fn f(&self);
}
struct I;
impl A for I {
fn f(&self) {
println!("A for I")
}
}
struct S {
a: Box<A + Send>
}
fn main() {
let s = S {
a: box I
};
s.a.f();
}
The other is setting the lifetime to 'a (we can put a reference &I or I to S):
trait A {
fn f(&self);
}
struct I;
impl A for I {
fn f(&self) {
println!("A for I")
}
}
impl <'a> A for &'a I {
fn f(&self) {
println!("A for &I")
}
}
struct S<'a> {
a: Box<A + 'a>
}
fn main() {
let s = S {
a: box &I
};
s.a.f();
}
Note that this is more general and we can store both references and owned data (Send kind that has a lifetime of 'static) but you require a lifetime parameter everywhere the type is used.
Related
In this question:
How to get a reference to a concrete type from a trait object?
Explains how to use Any to downcast a Trait. But I would like to downcast directly from the Trait to all the supported known types instead of using a generic as_any method. I tried:
pub trait A{
fn as_B(&self) -> B {
(&self as &dyn Any).downcast_ref::<B>().expect("Can't cast to B").clone()
}
}
impl A for B{}
But I get the error: lifetime may not live long enough cast requires that '1 must outlive 'static
I have tried:
Mark trait A as Clone, but this is not an option since this break other Traits that uses A and need those traits to be object traits.
Put life time parameters in the trait. This litter a lot of places where my trait A is used and in the end I get the same compilation error.
Remove & from self. But is neither an option since A size is not known.
Edited:
If you just want what Any does without going through it here rust playground, this is UB since Any is meant to translate to usable type,
trait A{
// Edited from std::any::Any downcast_ref_unchecked there is a checked version if you want to look
fn downcast_ref_unchecked(&self) -> &B where Self: Sized{
// Don't ask me how this works but I believe it dips into C land of pointers
unsafe { &*(self as *const dyn A as *const B) }
}
}
// Target
#[derive(Debug)]
struct B;
// Test
#[derive(Debug)]
struct C;
// Have test struct have 'A' trait
impl A for C {}
fn main(){
let t = C{};
println!("{:?}", t.downcast_ref_unchecked());
println!("{:?}", t);
}
I've got this code snippet (playground):
struct TeddyBear {
fluffiness: u8,
}
trait Scruffy {
fn scruff_up(self: &mut Box<Self>) -> Box<dyn Scruffy>;
}
impl Scruffy for TeddyBear {
fn scruff_up(self: &mut Box<Self>) -> Box<dyn Scruffy> {
// do something about the TeddyBear's fluffiness
}
}
It doesn't compile. The error is:
the trait Scruffy cannot be made into an object
, along with the hint:
because method scruff_up's self parameter cannot be dispatched on.
I checked the "E0038" error description, but I haven't been able to figure out which category my error falls into.
I also read the "object-safety" entry in "The Rust Reference", and I believe this matches the "All associated functions must either be dispatchable from a trait object", but I'm not sure, partly because I'm not sure what "receiver" means in that context.
Can you please clarify for me what's the problem with this code and why it doesn't work?
The problem is when you pass it in as a reference, because the inner type may not be well-sized (e.g. a trait object, like if you passed in a Box<Fluffy>) the compiler doesn't have enough information to figure out how to call methods on it. If you restrict it to sized objects (like your TeddyBear) it should compile
trait Scruffy {
fn scruff_up(self: &mut Box<Self>) -> Box<dyn Scruffy> where Self: Sized;
}
A receiver is the self (&self, &mut self, self: &mut Box<Self> and so on).
Note that the list you cited from the reference lists both Box<Self> and &mut Self, but does not list &mut Box<Self> nor it says that combinations of these types are allowed.
This is, indeed, forbidden. As for the why, it is a little more complex.
In order for a type to be a valid receiver, it needs to hold the following condition:
Given any type Self that implements Trait and the receiver type Receiver, the receiver type should implement DispatchFromDyn<dyn Trait> for itself with all Self occurrences of Self replaced with dyn Trait.
For instance:
&self (has the type &Self) has to implement DispatchFromDyn<&dyn Trait>, which it does.
Box<Self> has to implement DispatchFromDyn<Box<dyn Trait>>, which it does.
But in order for &mut Box<Self> to be an object-safe receiver, it would need to impl DispatchFromDyn<&mut Box<dyn Trait>>. What you want is kind of blanket implementation DispatchFromDyn<&mut T> for &mut U where U: DispatchFromDyn<T>.
This impl will never exist. Because it is unsound (even ignoring coherence problems).
As explained in the code in rustc that calculates this:
The only case where the receiver is not dispatchable, but is still a valid receiver type (just not object-safe), is when there is more than one level of pointer indirection. E.g., self: &&Self, self: &Rc<Self>, self: Box<Box<Self>>. In these cases, there is no way, or at least no inexpensive way, to coerce the receiver from the version where Self = dyn Trait to the version where Self = T, where T is the unknown erased type contained by the trait object, because the object that needs to be coerced is behind a pointer.
The problem is inherent to how Rust handles dyn Trait.
dyn Trait is a fat pointer: it is actually two words sized. One is a pointer to the data, and the other is a pointer to the vtable.
When you call a method on dyn Trait, the compiler looks up in the vtable, find the method for the concrete type (which is unknown at compilation time, but known at runtime), and calls it.
This all may be very abstract without an example:
trait Trait {
fn foo(&self);
}
impl Trait for () {
fn foo(&self) {}
}
fn call_foo(v: &dyn Trait) {
v.foo();
}
fn create_dyn_trait(v: &impl Trait) {
let v: &dyn Trait = v;
call_foo(v);
}
The compiler generates code like:
trait Trait {
fn foo(&self);
}
impl Trait for () {
fn foo(&self) {}
}
struct TraitVTable {
foo: fn(*const ()),
}
static TRAIT_FOR_UNIT_VTABLE: TraitVTable = TraitVTable {
foo: unsafe { std::mem::transmute(<() as Trait>::foo) },
};
type DynTraitRef = (*const (), &'static TraitVTable);
impl Trait for dyn Trait {
fn foo(self: DynTraitRef) {
(self.1.foo)(self.0)
}
}
fn call_foo(v: DynTraitRef) {
v.foo();
}
fn create_dyn_trait(v: &impl Trait) {
let v: DynTraitRef = (v as *const (), &TRAIT_FOR_UNIT_VTABLE);
call_foo(v);
}
Now suppose that the pointer to the value is behind an indirection. I'll use Box<&self> because it's simple but demonstrates the concept best, but the concept applies to &mut Box<Self> too: they have the same layout. How will we write foo() for impl Trait for dyn Trait?
trait Trait {
fn foo(self: Box<&Self>);
}
impl Trait for () {
fn foo(self: Box<&Self>) {}
}
struct TraitVTable {
foo: fn(Box<*const ()>),
}
static TRAIT_FOR_UNIT_VTABLE: TraitVTable = TraitVTable {
foo: unsafe { std::mem::transmute(<() as Trait>::foo) },
};
type DynTraitRef = (*const (), &'static TraitVTable);
impl Trait for dyn Trait {
fn foo(self: Box<DynTraitRef>) {
let concrete_foo: fn(Box<*const ()>) = self.1.foo;
let data: *const () = self.0;
concrete_foo(data) // We need to wrap `data` in `Box`! Error.
}
}
You may think "then the compiler should just insert a call to Box::new()!" But besides Box not being the only one here (what with Rc, for example?) and we will need some trait to abstract over this behavior, Rust never performs any hard work implicitly. This is a design choice, and an important one (as opposed to e.g. C++, where an innocent-looking statement like auto v1 = v; can allocate and copy 10GB by a copy constructor). Converting a type to dyn Trait and back is done implicitly: the first one by a coercion, the second one when you call a method of the trait. Thus, the only thing that Rust does for that is attaching a VTable pointer in the first case, or discarding it in the second case. Even allowing only references (&&&Self, no need to call a method, just take the address of a temporary) exceeds that. And it can have severe implications in unexpected places, e.g. register allocation.
So, what to do? You can take &mut self or self: Box<Self>. Which one to choose depends on whether you need ownership (use Box) or not (use a reference). And anyway, &mut Box<Self> is not so useful (its only advantage over &mut T is that you can replace the box and not just its contents, but when you do that that's usually a mistake).
Rust supports trait inheritance, as follows:
pub trait A {}
pub trait B: A {}
B: A means that if some type T implements B, it also needs to implement all the methods in A.
But today I see the following code:
trait Display: 'static {
fn print(&self);
}
What does it mean? It doesn't seem to be trait inheritance.
Rust supports trait inheritance, as follows [...] B: A means that if some type T implements B, it also needs to implement all the methods in A.
Technically, that is not inheritance but requirement. It is a trait bound not entirely dissimilar to one you'd have in a function: it constraints the type on which B is implementable to only types on which A is already implemented.
With that change in wording, the second version is much easier to understand: it's a lifetime bound, meaning it constraints the type on which B is implementable to only types with 'static lifetime, meaning if you're trying to implement B on a type, that must either have no lifetime at all, or have a 'static lifetime (or the implementation must have a lifetime bound aka only work for some uses of the type).
You can see that if you try to implement the trait on a lifetime-generic structure:
struct A<'a>(&'a str);
trait Display: 'static {
fn print(&self);
}
impl <'a>Display for A<'a> {
fn print(&self) { todo!() }
}
will yield
error[E0478]: lifetime bound not satisfied
That is because 'a can be anything, so implementing Display for A<'a> means it is also implemented for non-'static instances, which is not valid.
By adding the relevant lifetime bound on the impl, and thus limiting the implementation to A<'static> instances:
struct A<'a>(&'a str);
trait Display: 'static {
fn print(&self);
}
impl <'a: 'static>Display for A<'a> {
fn print(&self) { todo!() }
}
the requirements of the trait are satisfied, and the impl is valid (nb: the 'a is not necessary here you can just impl ... for A<'static>, I'm showing it for regularity).
And if your struct has no lifetime it works by default, because no lifetime ~ 'static:
struct A(String);
trait Display: 'static {
fn print(&self);
}
impl Display for A {
fn print(&self) { todo!() }
}
Rust doesn't have inheritance.
What it has is a way to define constraints. For example a trait may be constrained to only be implemented by types which implement another trait.
In your case the constraint is a lifetime bound.
To implement your Display trait, an object may contain references but in this case their lifetime must respect this constraint.
Let's suppose you have this type:
struct S<'a> {
s: &'a str,
}
Then you can't implement the trait for any lifetime, but only 'static.
impl Display for S<'static> {
fn print(&self){}
}
fn main() {
let s1 = "test";
let a = S { s: s1 };
a.print(); // compiles
let s2 = "test".to_string();
let a = S { s: &s2 };
a.print(); // doesn't compile because s doesn't live long enough
}
I want to write a piece of code that can take references or owned values of a copyable type, and return an owned version of that type. I've reduced the problems I'm having with the type inference to the following code, which errors:
use std::borrow::Borrow;
fn copy<R, E>(val: E) -> R
where
R: Default + Copy,
E: Borrow<R>,
{
*val.borrow()
}
fn main() {
assert_eq!(6, copy(&6));
assert_eq!(6, copy(6));
assert_eq!(6.0, copy(&6.0));
assert!((6.0f64 - copy(&6.0f64)).abs() < 1e-6);
}
The error comes from the last assert:
error[E0282]: type annotations needed
--> src/main.rs:15:13
|
15 | assert!((6.0f64 - copy(&6.0f64)).abs() < 1e-6);
| ^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
|
= note: type must be known at this point
My only hypothesis that the Sub trait on f64 allows f64 or &f64, and if the Default constraint weren't there, then a valid expression for the last copy would be copy::<&f64, &f64>(&6.0f64), however that isn't allowed because &f64 doesn't implement Default. If we pass in an f64 by value it works, presumably because then it restricts R to be f64 instead of either.
What I'm not clear on is why the compiler can't further restrict the return type of copy, or how to indicate to the compiler that the value returned won't be a reference.
Nothing in copy constrains R to a specific concrete type. In particular, &f64 could implement Borrow<R> for multiple values of R (not just f64). It doesn't in your current code, but the lack of alternatives is not considered grounds to pick a specific implementation.
I can even add an implementation that matches:
#[derive(Copy, Clone, Debug, Default)]
struct Foo;
impl Borrow<Foo> for &f64 {
fn borrow(&self) -> &Foo { &Foo }
}
(This trait implementation is permitted even though f64 is a standard library type because Foo is a type defined in the current crate.)
Now we can actually use the choice:
fn main() {
dbg!(copy::<f64, _>(&1.0));
dbg!(copy::<Foo, _>(&1.0));
}
[src/main.rs:19] copy::<f64, _>(&1.0) = 1.0
[src/main.rs:20] copy::<Foo, _>(&1.0) = Foo
A function like copy can only have its return type derived from its argument type when the return type actually depends on the argument type: for example, if it is an associated type of trait implemented by the argument. Both AsRef and Borrow have a type parameter rather than an associated type (and can therefore be implemented multiple times for the same implementing type); Deref has an associated Target type instead, but Deref doesn't offer going from f64 to f64. You could implement your own trait for this:
trait DerefCopy: Copy {
type Output;
fn deref_copy(self) -> Self::Output;
}
impl<T: Copy> DerefCopy for &T {
type Output = T;
fn deref_copy(self) -> T {
*self
}
}
impl DerefCopy for f64 {
type Output = Self;
fn deref_copy(self) -> Self {
self
}
}
fn main() {
assert_eq!(6, (&6).deref_copy());
assert_eq!(6, (6).deref_copy());
assert_eq!(6.0, (&6.0).deref_copy());
assert!((6.0f64 - (&6.0f64).deref_copy()).abs() < 1e-6);
}
However, this would require you to implement DerefCopy for every non-reference type you wish to use it with, because it's not possible to write a blanket implementation for all non-reference Ts; the reason Borrow can have a blanket implementation is that impl Borrow<T> for T doesn't conflict with impl Borrow<T> for &T because if we suppose T is itself a reference &U, we get impl Borrow<&U> for &&U which is still not the same as impl Borrow<T> for T.
This used to work:
struct Foo<'a, T> {
parent:&'a (Array<T> + 'a)
}
impl<'a, T> Foo<'a, T> { //'
pub fn new<T>(parent:&Array<T>) -> Foo<T> {
return Foo {
parent: parent
};
}
}
trait Array<T> {
fn as_foo(&self) -> Foo<T> {
return Foo::new(self);
}
}
fn main() {
}
Now it errors:
:15:21: 15:25 error: the trait core::kinds::Sized is not implemented for the type Self
:15 return Foo::new(self);
I can kind of guess what's wrong; it's saying that my impl of Foo<'a, T> is for T, not Sized? T, but I'm not trying to store a Sized? element in it; I'm storing a reference to a Sized element in it. That should be a pointer, fixed size.
I don't see what's wrong with what I'm doing, or why it's wrong?
For example, I should (I think...) be able to store a &Array in my Foo, no problem. I can't see any reason this would force my Foo instance to be unsized.
playpen link: http://is.gd/eZSZYv
There's two things going on here: trait objects coercions (the error), and object safety (fixing it).
The error
As suggested by the error message, the difficult part of the code is the Foo::new(self), and this is because pub fn new<T>(parent: &Array<T>) -> ..., that is, self is being coerced to an &Array<T> trait object. I'll simplify the code to:
trait Array {
fn as_foo(&self) {
let _ = self as &Array; // coerce to a trait object
}
}
fn main() {}
which gives the same thing:
<anon>:3:13: 3:27 error: the trait `core::kinds::Sized` is not implemented for the type `Self`
<anon>:3 let _ = self as &Array; // coerce to a trait object
^~~~~~~~~~~~~~
Self is the stand-in name for the type that implements the trait. Unlike most generic parameters, Self is possibly-unsized (?Sized) by default, since RFC 546 and #20341 for the purposes of allowing e.g. impl Array<T> for Array<T> to work by default more often (we'll come to this later).
The variable self has type &Self. If Self is a sized type, then this is a normal reference: a single pointer. If Self is an unsized type (like [T] or a trait), then &Self (&[T] or &Trait) is a slice/trait object: a fat pointer.
The error appears because the only references &T that can be cast to a trait object are when T is sized: Rust doesn't support making fat pointers fatter, only thin pointer → fat pointer is valid. Hence, since the compiler doesn't know that Self will always be Sized (remember, it's special and ?Sized by default) it has to assume the worst: that the coercion is not legal, and so it's disallowed.
Fixing it
It seems logical that the fix we're looking for is to ensure that Self: Sized when we want to do a coercion. The obvious way to do this would be to make Self always Sized, that is, override the default ?Sized bound as follows:
trait Array: Sized {
fn as_foo(&self) {
let _ = self as &Array; // coerce to a trait object
}
}
fn main() {}
Looks good!
Except there's the small point that it doesn't work; but at least it's for a difference reason, we're making progress! Trait objects can only be made out of traits that are "object safe" (i.e. safe to be made into a trait object), and having Sized Self is one of the things that breaks object safety:
<anon>:3:13: 3:17 error: cannot convert to a trait object because trait `Array` is not object-safe [E0038]
<anon>:3 let _ = self as &Array; // coerce to a trait object
^~~~
<anon>:3:13: 3:17 note: the trait cannot require that `Self : Sized`
<anon>:3 let _ = self as &Array; // coerce to a trait object
^~~~
<anon>:3:13: 3:17 note: the trait cannot require that `Self : Sized`
<anon>:3 let _ = self as &Array; // coerce to a trait object
^~~~
(I filed the double printing of the note as #20692.)
Back to the drawing board. There's a few other "easy" possibilities for a solution:
define an extension trait trait ArrayExt: Sized + Array { fn as_foo(&self) { ... } } and implement it for all Sized + Array types
just use a free function fn array_as_foo<A: Array>(x: &A) { ... }
However, these don't necessarily work for every use case, e.g. specific types can't customise the behaviour by overloading the default method. However, fortunately there is a fix!
The Turon Trick
(Named for Aaron Turon, who discovered it.)
Using generalised where clauses we can be highly specific about when Self should implement Sized, restricting it to just the method(s) where it is required, without infecting the rest of the trait:
trait Array {
fn as_foo(&self) where Self: Sized {
let _ = self as &Array; // coerce to a trait object
}
}
fn main() {}
This compiles just fine! By using the where clause like this, the compiler understands that (a) the coercion is legal because Self is Sized so self is a thin pointer, and (b) that the method is illegal to call on a trait object anyway, and so doesn't break object safety. To see it being disallowed, changing the body of as_foo to
let x = self as &Array; // coerce to a trait object
x.as_foo();
gives
<anon>:4:7: 4:15 error: the trait `core::kinds::Sized` is not implemented for the type `Array`
<anon>:4 x.as_foo();
^~~~~~~~
as expected.
Wrapping it all up
Making this change to the original unsimplified code is as simple adding that where clause to the as_foo method:
struct Foo<'a, T> { //'
parent:&'a (Array<T> + 'a)
}
impl<'a, T> Foo<'a, T> {
pub fn new(parent:&Array<T>) -> Foo<T> {
return Foo {
parent: parent
};
}
}
trait Array<T> {
fn as_foo(&self) -> Foo<T> where Self: Sized {
return Foo::new(self);
}
}
fn main() {
}
which compiles without error. (NB. I had to remove the unnecessary <T> in pub fn new<T> because that was causing inference failures.)
(I have some in-progress blog posts that go into trait objects, object safety and the Turon trick, they will appear on /r/rust in the near future: first one.)