How to downcast a Trait in rust directly from the Trait itself - rust

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);
}

Related

Rust: additional trait bounds in conjunction with higher-ranked lifetime bounds

I want trait implementations in Rust to be able to return arbitrary iterators (of specific item type) that may reference the original object with a lifetime 'a without having to explicitly mention 'a in the trait generics and everywhere where the trait is used or otherwise introducing significant trait bound bloat to user code. The only simple way I've figured to do this is that the trait has to be implemented for &'a MyStruct instead of MyStruct (this approach is used in some places in the standard library), but the significant drawback is that in generic code wrappers cannot “own” implementations of the trait (MyStruct) without exposing the lifetime in trait bounds all over the code. So nothing gained when ownership is needed.
Another way I figured out that should work (just done the simple test below so far) is to use higher-ranked lifetime bounds on a “base trait” that would implement the iterator-generation functions. In the code below Foo is the main trait, FooInterfaceGen is the iterator-generator trait that has its lifetime “hidden” through for <'a> when assumed as a super-trait of Foo. The FooInterface generated by FooInterfaceGen would be the trait for an appropriate type of iterator when modified to that application of the idea. However, it seems impossible to make additional trait bounds on the specific implementation FooInterfaceGen::Interface. The code below works, but when you uncomment the Asdf trait bound in the function footest, the compiler complains that
the trait `for<'a> Asdf` is not implemented for `<_ as FooInterfaceGen<'a>>::Interface
But I have implemented Asdf! It's as if the compiler is ignoring the 'a in the expression <T as FooInterfaceGen<'a>> and just applying for<'a> to the right-hand-side. Any ideas if this is a compiler bug, a known restriction, or of any ways around it?
trait FooInterface<'a> {
fn foo(&self) -> u32;
}
trait FooInterfaceGen<'a> {
type Interface : FooInterface<'a>;
fn gen(&'a self) -> Self::Interface;
}
trait Foo : for<'a> FooInterfaceGen<'a> { }
struct S2;
struct S1(S2);
impl<'a> FooInterfaceGen<'a> for S1 {
type Interface = &'a S2;
fn gen(&'a self) -> Self::Interface { &self.0 }
}
impl Foo for S1 { }
impl<'a> FooInterface<'a> for &'a S2 {
fn foo(&self) -> u32 { 42 }
}
trait Asdf {}
impl<'a> Asdf for &'a S2 {}
fn footest<T : Foo>(a : &T) -> u32
/* where for<'a> <T as FooInterfaceGen<'a>>::Interface : Asdf */ {
a.gen().foo()
}
fn main() {
let q = S1(S2);
println!("{}", footest(&q));
}
(Regarding some alternative implementations, maybe there's a technical reason for it, but otherwise I really don't understand the reason behind the significant trait bound bloat that Rust code easily introduces. Assuming a trait should in any reasonable situation automatically assume all the trait bound as well, also in generic code, not just specific code, without having to copy-paste an increasing number of where-clauses all over the code.)
The error seems to be a known compiler bug: https://github.com/rust-lang/rust/issues/89196

TryFrom<&[u8]> trait bound in trait

I'm trying to implement common trait for a bunch of types created from binary data (read from a disk). Majority of trait methods could use default implementations and only conversions etc. would be needed to be implemented separately. I would like to use TryFrom<&[u8]> trait for conversions from binary data to my types but I don't know how to express (in the context of trait) that lifetime of &[u8] and lifetimes of values of my types created from it are not related. Here is minimal example of the problem.
use std::convert::TryFrom;
struct Foo;
// Value of Foo can be created from &[u8] but it doesn't borrow anything.
impl TryFrom<&[u8]> for Foo {
type Error = ();
fn try_from(v: &[u8]) -> Result<Self, ()> {
Ok(Foo)
}
}
trait Bar<'a>
where
Self: TryFrom<&'a [u8], Error = ()>, // `&` without an explicit lifetime name cannot be used here
{
fn baz() -> Self {
let vec = Vec::new();
Self::try_from(&vec).unwrap() // ERROR: vec does not live long enough (nothing is borrowed)
}
}
Alternative solution would be to make conversions as trait methods but it would be nicer to use common std traits. Is there a way to achieve this? (Or I could use const generics but I don't want to rely on nightly compiler.)
What you want are "higher ranked trait bounds" (HRTB, or simply hearty boy). They look like this: for<'a> T: 'a. This example just means: "for every possible lifetime 'a, T must ...". In your case:
trait Bar
where
Self: for<'a> TryFrom<&'a [u8], Error = ()>,
You can also specify that requirement as super trait bound directly instead of where clause:
trait Bar: for<'a> TryFrom<&'a [u8], Error = ()> { ... }
And yes, now it just means that all implementors of Bar have to implement TryFrom<&'a [u8], Error = ()> for all possible lifetimes. That's what you want.
Working Playground

How do I deal with wrapper type invariance in Rust?

References to wrapper types like &Rc<T> and &Box<T> are invariant in T (&Rc<T> is not a &Rc<U> even if T is a U). A concrete example of the issue (Rust Playground):
use std::rc::Rc;
use std::rc::Weak;
trait MyTrait {}
struct MyStruct {
}
impl MyTrait for MyStruct {}
fn foo(rc_trait: Weak<MyTrait>) {}
fn main() {
let a = Rc::new(MyStruct {});
foo(Rc::downgrade(&a));
}
This code results in the following error:
<anon>:15:23: 15:25 error: mismatched types:
expected `&alloc::rc::Rc<MyTrait>`,
found `&alloc::rc::Rc<MyStruct>`
Similar example (with similar error) with Box<T> (Rust Playground):
trait MyTrait {}
struct MyStruct {
}
impl MyTrait for MyStruct {}
fn foo(rc_trait: &Box<MyTrait>) {}
fn main() {
let a = Box::new(MyStruct {});
foo(&a);
}
In these cases I could of course just annotate a with the desired type, but in many cases that won't be possible because the original type is needed as well. So what do I do then?
What you see here is not related to variance and subtyping at all.
First, the most informative read on subtyping in Rust is this chapter of Nomicon. You can find there that in Rust subtyping relationship (i.e. when you can pass a value of one type to a function or a variable which expects a variable of different type) is very limited. It can only be observed when you're working with lifetimes.
For example, the following piece of code shows how exactly &Box<T> is (co)variant:
fn test<'a>(x: &'a Box<&'a i32>) {}
fn main() {
static X: i32 = 12;
let xr: &'static i32 = &X;
let xb: Box<&'static i32> = Box::new(xr); // <---- start of box lifetime
let xbr: &Box<&'static i32> = &xb;
test(xbr); // Covariance in action: since 'static is longer than or the
// same as any 'a, &Box<&'static i32> can be passed to
// a function which expects &'a Box<&'a i32>
//
// Note that it is important that both "inner" and "outer"
// references in the function signature are defined with
// the same lifetime parameter, and thus in `test(xbr)` call
// 'a gets instantiated with the lifetime associated with
// the scope I've marked with <----, but nevertheless we are
// able to pass &'static i32 as &'a i32 because the
// aforementioned scope is less than 'static, therefore any
// shared reference type with 'static lifetime is a subtype of
// a reference type with the lifetime of that scope
} // <---- end of box lifetime
This program compiles, which means that both & and Box are covariant over their respective type and lifetime parameters.
Unlike most of "conventional" OOP languages which have classes/interfaces like C++ and Java, in Rust traits do not introduce subtyping relationship. Even though, say,
trait Show {
fn show(&self) -> String;
}
highly resembles
interface Show {
String show();
}
in some language like Java, they are quite different in semantics. In Rust bare trait, when used as a type, is never a supertype of any type which implements this trait:
impl Show for i32 { ... }
// the above does not mean that i32 <: Show
Show, while being a trait, indeed can be used in type position, but it denotes a special unsized type which can only be used to form trait objects. You cannot have values of the bare trait type, therefore it does not even make sense to talk about subtyping and variance with bare trait types.
Trait objects take form of &SomeTrait or &mut SomeTrait or SmartPointer<SomeTrait>, and they can be passed around and stored in variables and they are needed to abstract away the actual implementation of the trait. However, &T where T: SomeTrait is not a subtype of &SomeTrait, and these types do not participate in variance at all.
Trait objects and regular pointers have incompatible internal structure: &T is just a regular pointer to a concrete type T, while &SomeTrait is a fat pointer which contains a pointer to the original value of a type which implements SomeTrait and also a second pointer to a vtable for the implementation of SomeTrait of the aforementioned type.
The fact that passing &T as &SomeTrait or Rc<T> as Rc<SomeTrait> works happens because Rust does automatic coercion for references and smart pointers: it is able to construct a fat pointer &SomeTrait for a regular reference &T if it knows T; this is quite natural, I believe. For instance, your example with Rc::downgrade() works because Rc::downgrade() returns a value of type Weak<MyStruct> which gets coerced to Weak<MyTrait>.
However, constructing &Box<SomeTrait> out of &Box<T> if T: SomeTrait is much more complex: for one, the compiler would need to allocate a new temporary value because Box<T> and Box<SomeTrait> has different memory representations. If you have, say, Box<Box<T>>, getting Box<Box<SomeTrait>> out of it is even more complex, because it would need creating a new allocation on the heap to store Box<SomeTrait>. Thus, there are no automatic coercions for nested references and smart pointers, and again, this is not connected with subtyping and variance at all.
In the case of Rc::downgrade this is actually just a failure of the type inference in this particular case, and will work if it is done as a separate let:
fn foo(rc_trait: Weak<MyTrait>) {}
fn main() {
let a = Rc::new(MyStruct {});
let b = Rc::downgrade(&a);
foo(b);
}
Playground
For Box<T> it is very likely you don't actually want a reference to the box as the argument, but a reference to the contents. In which case there is no invariance to deal with:
fn foo(rc_trait: &MyTrait) {}
fn main() {
let a = Box::new(MyStruct {});
foo(a.as_ref());
}
Playground
Similarly, for the case with Rc<T>, if you write a function that takes an Rc<T> you probably want a clone (i.e. a reference counted reference), and not a normal reference:
fn foo(rc_trait: Rc<MyTrait>) {}
fn main() {
let a = Rc::new(MyStruct {});
foo(a.clone());
}
Playground

What is 'core::kinds::Sized` is not implemented for the type `Self' in rust?

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.)

Why "explicit lifetime bound required" for Box<T> in struct?

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.

Resources