Trait Object is not Object-safe error - rust

The following code does not compile for me.
trait A {
fn fun0(&self);
fn fun2(&self) -> Option<Box<Self>>;
}
struct B0 {
id: usize,
}
impl A for B0 {
fn fun0(&self) { println!("Value: {:?}", self.id); }
fn fun2(&self) -> Option<Box<Self>> { Option::None }
}
struct B1 {
id: isize,
}
impl A for B1 {
fn fun0(&self) { println!("Value: {:?}", self.id); }
fn fun2(&self) -> Option<Box<Self>> { Option::Some(Box::new(B1 { id: self.id, })) }
}
enum C {
None,
Put { object: Box<A>, },
}
fn fun1(values: Vec<C>) {
for it in values.iter() {
match *it {
C::Put { object: ref val, } => val.fun0(),
C::None => (),
};
}
}
fn main() {
let obj_b0 = Box::new(B0 { id: 778, });
let obj_b1 = Box::new(B1 { id: -8778, });
let obj_c0 = C::Put { object: obj_b0, };
let obj_c1 = C::Put { object: obj_b1, };
let mut vec = Vec::new();
vec.push(obj_c0);
vec.push(obj_c1);
fun1(vec);
}
gives an error:
cargo run
Compiling misc v0.0.1 (file:///home/spandan/virtualization/coding/my/rust-tests/misc/misc)
src/main.rs:188:48: 188:54 error: the trait `A` is not implemented for the type `A` [E0277]
src/main.rs:188 C::Put { object: ref val, } => val.fun0(),
^~~~~~
src/main.rs:197:35: 197:41 error: cannot convert to a trait object because trait `A` is not object-safe [E0038]
src/main.rs:197 let obj_c0 = C::Put { object: obj_b0, };
^~~~~~
src/main.rs:197:35: 197:41 note: method `fun2` references the `Self` type in its arguments or return type
src/main.rs:197 let obj_c0 = C::Put { object: obj_b0, };
^~~~~~
src/main.rs:198:35: 198:41 error: cannot convert to a trait object because trait `A` is not object-safe [E0038]
src/main.rs:198 let obj_c1 = C::Put { object: obj_b1, };
^~~~~~
src/main.rs:198:35: 198:41 note: method `fun2` references the `Self` type in its arguments or return type
src/main.rs:198 let obj_c1 = C::Put { object: obj_b1, };
^~~~~~
error: aborting due to 3 previous errors
Could not compile `misc`.
working with
rustc --version
rustc 1.0.0-nightly (00978a987 2015-04-18) (built 2015-04-19)
The problem appears when fun2(&self) is brought into the picture. It compiles and runs fine if fun0 is the only existing function in the trait. But my code needs such a pattern - How do i do it ?
Edit: the correct answer for the above has been given here (https://stackoverflow.com/a/29985438/1060004) . But i am running into the same problem if i remove the &self from function signature (ie., make it static):
fn fun2() -> Option<Box<A>>
what is the issue now ?

As you have noticed, the problem vanishes when you remove fun2 method. Let's look at it more closely:
fn fun2(&self) -> Option<Box<Self>>;
Note that its output type contains Self, that is, the type which the trait is implemented for. For example, if A is implemented for String, it would be String:
impl A for String {
fn fun2(&self) -> Option<Box<String>> { ... }
}
However! With the trait objects the actual type of the value is erased, and the only thing that we know about trait objects is that it is a value which implements the trait, but we don't know the actual type the trait is implemented for. Trait object methods are dispatched dynamically, so the program selects the actual method to call at runtime. These methods have to behave identically, that is, accept the same number of parameters of the same size (pairwise) and return values of the same size too. If a method uses Self somewhere in its signature, like fun2, its implementations won't be compatible with each other because they would need to operate on values of different size, and hence such methods can't be unified.
Such methods (which can't work with trait objects) are called object-unsafe (or not object-safe). If a trait contains such methods, it can't be made a trait object - it is also called not object-safe.
What would work, I believe, is that you can make the trait return a trait object:
fn fun2(&self) -> Option<Box<A>>
Now the dependency on the actual type is lifted, and the trait becomes object-safe again.

Well, the error message pretty much spells out the immediate problem: you're trying to use a non-object-safe trait in an object context, and you can't do that.
You can remove fun2 from the trait A, and define it in a different trait: its presence will prevent A from ever being used as a "trait object"; so &A, Box<A>, etc. will all out of the question. Each type can then implement both of these traits.
Another alternative is to change fun2 so that its result does not contain the Self type; your example is too abstract to know, but would Option<Box<A>> be acceptable?
As for why: in order for a trait to be used as a trait object, the compiler has to be able to generate a vtable for the trait's methods so that it can do dynamic, runtime dispatch. This means that every method in the trait has to be implementable with the same types (the self parameter is a special case). So what does fun2 return? It has to return an Option<Box<Self>>, but Self is a different type for every implementation! There's no possible way to unify it!

Related

What exactly is the requirement for "covering" a type & why does a single element tuple satisfy it?

Assuming the following code is present
use core::any::Any;
enum Value {
Any(Box<dyn Any>),
Other, // placeholder, this code is adapted from mine
}
This code raises a diagnostic that I can't quite understand
impl<T: Any> TryFrom<Value> for T {
type Error = &'static str;
fn try_from(val: Value) -> Result<Self, Self::Error> {
if let Value::Any(any) = val {
if let Ok(down) = any.downcast::<T>() {
Ok(*down)
} else {
Err("incorrect type")
}
} else { Err("not an any") }
}
}
fn main() {
let res: Result<usize, &'static str> = Value::Any(Box::new(1usize)).try_into();
dbg!(res);
}
error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Value`)
--> src/main.rs:9:6
|
9 | impl<T: Any> TryFrom<Value> for T {
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`Value`)
|
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
I still don't quite understand what "must be covered by another type" means, nor "when it appears before the first local type".
However, if I modify the impl signature to target a single-element tuple containing T, the impl does not raise an error, and the code functions correctly:
impl<T: Any> TryFrom<Value> for (T,) {
type Error = &'static str;
fn try_from(val: Value) -> Result<Self, Self::Error> {
if let Value::Any(any) = val {
if let Ok(down) = any.downcast::<T>() {
Ok((*down,))
} else {
Err("incorrect type")
}
} else { Err("not an any") }
}
}
fn main() {
let res: Result<(usize,), &'static str> = Value::Any(Box::new(1usize)).try_into();
dbg!(res);
}
What purpose does the single-element tuple actually serve?
(Playground Link)
From RFC 2451:
Covered Type: A type which appears as a parameter to another type. For example, T is uncovered, but the T in Vec<T> is covered. This is only relevant for type parameters.
It is important to note that the type T does not equal the tuple type (T,). (T,) can be considered equivalent to a hypothetical generic newtype/tuple struct struct Tuple1<T>(T) defined in the standard library crate std. With this analogy, impl<T: Any> TryFrom<Value> for (T,) is equivalent to impl<T: Any> TryFrom<Value> for std::Tuple1<T>.
Note that the covering type (in this case the single element tuple type, or in our analogy Tuple1) need not be defined locally in the same crate. To put it simply, consider an impl<T> ForeignTrait<LocalType> for ForeignType<T>:
The covering type ForeignType has already been defined. So:
The only way ForeignTrait<LocalType> can be implemented for
ForeignType<T> outside of the current crate is through a generic
impl <S, T> ForeignTrait<S> for ForeignType<T> (where S covers
LocalType).
Because of these rules, an impl <S, T> ForeignTrait<S> for ForeignType<T> that covers ForeignTrait<LocalType> is only possible in the crate declaring ForeignType.
Hence it is impossible for a conflicting implementation of ForeignTrait<LocalType> to exist for ForeignType<T> outside of a) the local crate and b) the crate declaring ForeignType, and so the impl is allowed. The RFC discusses this in more detail.

What code will actually be generated when a generic struct implements `Deref`?

I can't really understand the dereference here. The type of foo is TattleTell<&str>. The method len() is from foo.value, i.e. foo.value.len(). So why deref of TattleTell is invoked?
use std::ops::Deref;
struct TattleTell<T> {
value: T,
}
impl<T> Deref for TattleTell<T> {
type Target = T;
fn deref(&self) -> &T {
println!("{} was used!", std::any::type_name::<T>());
&self.value
}
}
fn main() {
let foo = TattleTell {
value: "secret message",
};
// dereference occurs here immediately
// after foo is auto-referenced for the
// function `len`
println!("{}", foo.len());
}
I won't fully describe Rust's auto-dereferencing rules because they are covered in other answers. For example, here.
In your case, you are trying to call a method, len, on a TattleTell<&'static str>. This type doesn't directly have that method so, using the rules in that other answer, Rust goes looking for it, using the following steps:
Check if the method exists on &TattleTell<&'static str>. It doesn't.
Check if the method exists on *&TattleTell<&'static str>. Due to your Deref implementation, this is a &'static str, so the method exists.

How to specify associated type <Item=...> when calling associated function of a trait?

I have this rust code playground:
use itertools::{repeat_n,RepeatN};
pub trait MyIterator: Iterator {
fn fill1(elem: Self::Item, n1: usize) -> RepeatN<Self::Item>
where
Self::Item: Clone,
{
repeat_n(elem, n1)
}
}
My Problem is that I can't call this method because rustc can't infer the type.
// error[E0284]: type annotations needed
// let r: RepeatN<char> = MyIterator::fill1('a', 5);
// ^^^^^^^^^^^^^^^^^ cannot infer type
// note: cannot satisfy `<_ as Iterator>::Item == _`
let r: RepeatN<char> = MyIterator::fill1('a', 5);
I tried this but it doesn't compile:
// error[E0229]: associated type bindings are not allowed here
let r: RepeatN<char> = MyIterator::<Item=char>::fill1('a', 5);
How can I specify the type of Item in this call? Or is a function outside of the trait (like itertools::repeat_n) the best way here?
Well, you haven't implemented the trait for any types, so no fill1 function actually exists.
If you implement MyIterator for some type that implements Iterator<Item = char>, for example std::iter::Empty<char>, then you'll be able to call fill1 through that type.
use std::iter::Empty;
impl MyIterator for Empty<char> {}
fn main() {
let r: RepeatN<char> = Empty::fill1('a', 5);
}
This is, however, pointless. You will note that Empty plays no role in the actual function definition - it could have been any iterator. Furthermore there is no sensible generalization of this behavior to other Self types. This is why itertools::repeat_n is not a member of the Itertools trait: it is nonsense as a trait function because it is not a generalization of behavior shared by multiple iterator types.
In Rust, unlike some other languages, not everything has to be a member of a class. If you merely want to put fill1 and related things in a common namespace, simply use a module, which is the most basic unit of code organization.
mod my_iterator {
use itertools::{repeat_n, RepeatN};
fn fill1<T>(elem: T, n1: usize) -> RepeatN<T>
where
T: Clone,
{
repeat_n(elem, n1)
}
}

How does `.into()` know which type to convert to if `From` is implemented for multiple types?

How does the the <From> trait know which type to convert to in different contexts if it's implemented for more than one type?
For example, i have three types that have some mutual conversions implemented. On Character i implement From for both Token and AminoAcid. Yet, when i call .into() in the hashmap i don't have to specify which type is required by the map's type definition. How is the trait aware of the context?
#[derive(Debug)]
struct Coordinate{
x:f64, y:f64, z:f64
}
#[derive(Debug)]
enum AminoAcid {
VAL, GLN ,ARG,...
}
#[derive(Debug)]
enum Token {
Coordinate(Coordinate),
AminoAcid(AminoAcid),
Character(Character)
}
impl From<Coordinate> for Token {
fn from(coord: Coordinate) -> Self {
Self::Coordinate(coord)
}
}
impl From<AminoAcid> for Token {
fn from(aa: AminoAcid) -> Self {
Self::AminoAcid(aa)
}
}
// ------------------------------------------------- <<<<
impl From<Character> for Token {
fn from(c: Character) -> Self {
Self::Character(c)
}
}
impl From<Character> for AminoAcid {
fn from(c: Character) -> Self {
Self::ALA
}
}
// ------------------------------------------------- <<<<
lazy_static! {
static ref HASHMAP: HashMap<&'static str, Token> = { // Here the value type is Token
let mut m = HashMap::new();
m.insert("ALA", Character::Second.into());
m
};
static ref HASHMAP: HashMap<&'static str, AminoAcid> = { // Here the value type is AminoAcid
let mut m = HashMap::new();
m.insert("ALA", Character::Second.into());
m
};
}
It's because Rust can deduce/infer types.
For example
fn f1(arg: u8) {
println!("u8 in f1: {}", arg)
}
fn f2(arg: i64) {
println!("i64 in f2: {}", arg)
}
fn main() {
let a = 12;
let b = 23;
f1(a);
f2(b);
// f1(b); // expected `u8`, found `i64`
// f2(a); // expected `i64`, found `u8`
}
a and b are declared the same way; at this point, the compiler just knows they are some kind of integer.
At the first call of f1(), since the expected argument is an u8, Rust deduces that a is actually an u8.
The same goes for b deduced as an i64 at the first usage of f2().
Of course, if after that we try to make the compiler deduce other types for these variables, it fails.
In your case, you declare your static bindings as hashmaps of a specific type: Token in one case, AminoAcid in the other.
Then, the brace used to initialise such a binding have to match this type; the type of the resulting expression (m) is deduced accordingly.
The way we initialise m expects the correct value type.
Consequently, the version of into() providing this type is chosen.
Because you defined the type of HASHMAP, the compiler infers which type is needed, since if it converted into the other type it would not compile. https://doc.rust-lang.org/rust-by-example/types/inference.html

Why am I getting a "value must be known" error on tuple in a for-loop?

struct Plugin;
struct Blueprint<'a>(&'a ());
struct Shell<'a> {
plugins: Vec<(&'a Plugin, Vec<Blueprint<'a>>)>,
}
impl<'a> Shell<'a> {
fn find_blueprint(&self, name: &str) -> Option<Blueprint> {
for plugin_blueprints in self.plugins.as_ref() {
for blueprint in plugin_blueprints.1 {
if blueprint.name.to_string() == name {
return Some(blueprint);
}
}
}
None
}
}
fn main() {}
Generates this error:
error: the type of this value must be known in this context
--> src/main.rs:11:30
|
11 | for blueprint in plugin_blueprints.1 {
| ^^^^^^^^^^^^^^^^^^^
This confuses me because plugin_blueprints seems to be unambiguously of type (&'a Plugin, Vec<Blueprint<'a>>). I'm not sure what syntax (if any) I would use to specify the type in a for-loop. Turbo-fish ::< doesn't seem to work.
Because you are using as_ref, which is more generic than you want. The value of T cannot be inferred:
pub trait AsRef<T>
where T: ?Sized
{
fn as_ref(&self) -> &T;
}
The idiomatic way to iterate over this is
for plugin_blueprints in &self.plugins {}
The pretty nasty way of doing it is to use the turbofish on the trait, using the disambiguated function call syntax:
for plugin_blueprints in AsRef::<[(&'a Plugin, Vec<Blueprint<'a>>)]>::as_ref(&self.plugins) {
Your function will actually return a Option<&Blueprint> because you start with &self. You should also use self.plugins.iter() and plugin_blueprints.1.iter() to stop the ambiguity introduced by as_ref() and fix your lifetimes.
See here

Resources