Cloning an Rc pointer over a trait object in Rust? - rust

I am learning Rust and don't understand why the following doesnt work. I gather we are unable to clone an Rc pointer over a trait object? How am I to pass such a reference to an function defined only by a trait, as attempted in some_function?
use std::rc::Rc;
trait SomeTrait {}
struct SomeThing {}
impl SomeTrait for SomeThing {}
fn some_function(s: Rc<dyn SomeTrait>) {}
fn another_function(s: &Rc<dyn SomeTrait>) {}
fn main() {
let s = Rc::new(SomeThing{});
// This doesnt work
some_function(Rc::clone(&s));
// I could do this
some_function(s);
// But then I could not do this
some_function(s);
// For that matter, neither can I do this
another_function(&s);
}

If you look at the error messages of the compiler you will see this:
error[E0308]: mismatched types
|
14 | some_function(Rc::clone(&s));
| ^^ expected trait object `dyn SomeTrait`, found struct `SomeThing`
|
= note: expected reference `&Rc<dyn SomeTrait>`
found reference `&Rc<SomeThing>`
That means the compiler mis-infers the type of s to Rc<SomeThing> instead of the Rc<dyn SomeTrait> you were looking for, which can be confirmed by the usual trick of providing a blatantly incorrect type to let s:
error[E0308]: mismatched types
--> src/main.rs:11:17
|
11 | let s: () = Rc::new(SomeThing{});
| -- ^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Rc`
| |
| expected due to this
|
= note: expected unit type `()`
found struct `Rc<SomeThing>`
Since Rust wrappers are invariant, an Rc<SomeThing> and an Rc<dyn SomeTrait> are completely incompatible values, there is no way to just use one for the other.
The solution is to simply explicitely type s correctly:
use std::rc::Rc;
trait SomeTrait {}
struct SomeThing {}
impl SomeTrait for SomeThing {}
fn some_function(s: Rc<dyn SomeTrait>) {}
fn another_function(s: &Rc<dyn SomeTrait>) {}
fn main() {
let s: Rc<dyn SomeTrait> = Rc::new(SomeThing{});
// This doesnt work
some_function(Rc::clone(&s));
// For that matter, neither can I do this
another_function(&s);
}
Obviously the two calls in the middle can't work, as the first one will move the local Rc, which the second one (and the final call) still want.

Related

Why does MyEnum<T> requires T to implement the Clone trait to derive the Clone trait when T is never cloned? [duplicate]

It seems that when deriving Clone, Rust forwards the Clone trait requirement to Generics that do not require the trait, like if they are wrapped inside an Arc.
Do I misunderstand how Clone works or is this a compiler mistake?
Consider the following code, where a.clone() works, but b.clone() does not.
Also note that without the b.clone() call, the code compiles fine, indicating that #[derive(Clone)] worked.
use std::sync::Arc;
struct Unclonable {}
struct A<T>(Arc<T>);
impl<T> Clone for A<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
#[derive(Clone)]
struct B<T>(Arc<T>);
fn main() {
let a = A(Arc::new(Unclonable {}));
let b = B(Arc::new(Unclonable {}));
// Works
a.clone();
// Fails
b.clone();
}
|
3 | struct Unclonable {}
| ----------------- doesn't satisfy `Unclonable: Clone`
...
13 | struct B<T>(Arc<T>);
| --------------------
| |
| method `clone` not found for this
| doesn't satisfy `B<Unclonable>: Clone`
...
22 | b.clone();
| ^^^^^ method cannot be called on `B<Unclonable>` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`Unclonable: Clone`
which is required by `B<Unclonable>: Clone`
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `clone`, perhaps you need to implement it:
candidate #1: `Clone`
help: consider annotating `Unclonable` with `#[derive(Clone)]`
|
3 | #[derive(Clone)]
|
When I expand the macros, I see the following generated code:
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2018::*;
#[macro_use]
extern crate std;
use std::sync::Arc;
struct Unclonable {}
struct A<T>(Arc<T>);
impl<T> Clone for A<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
struct B<T>(Arc<T>);
#[automatically_derived]
#[allow(unused_qualifications)]
impl<T: ::core::clone::Clone> ::core::clone::Clone for B<T> {
#[inline]
fn clone(&self) -> B<T> {
match *self {
B(ref __self_0_0) => B(::core::clone::Clone::clone(&(*__self_0_0))),
}
}
}
fn main() {
let a = A(Arc::new(Unclonable {}));
let b = B(Arc::new(Unclonable {}));
a.clone();
b.clone();
}
What is going on?
Why would the Rust compiler add <T: ::core::clone::Clone>??
Or is this just one of those cases where the intended way is to implement Clone manually?
This is not a compiler bug, in the sense that it's a documented behavior, even though one might find it weird. The compiler will automatically add constraints to generic types when deriving, even if those constraints are not actually required in the implementation. For instance, deriving Clone for B<T> will only implement Clone for B<T> where T: Clone, even though it would be possibly to implement that regardless of whether T is Clone.
So, for the time being (maybe the compiler will get smarter about these cases in the future), yes, it's one of those cases where you have to implement manually.
If you don't mind a smallo dependency, you can avoid the drudgery1 of manual implementation using the derivative crate:
#[derive(Derivative)]
#[derivative(Clone(bound = ""))]
struct B<T>(Arc<T>);
Playground
1 In the case of a small struct the drudgery is not that bad, but in case of an enum with many variants, the implementation gets quite large.

Error when trying to implement a function declared in a supertrait

I'm trying to implement a trait that has a supertrait, like so:
trait A {
fn do_a(&self);
}
trait B: A {
fn do_b(&self);
}
struct S {}
impl B for S {
fn do_a(&self) {}
fn do_b(&self) {}
}
When I run cargo build I get these compiler errors:
error[E0407]: method `do_a` is not a member of trait `B`
--> src/example.rs:12:5
|
12 | fn do_a(&self) {}
| ^^^^^^^^^^^^^^^^^ not a member of trait `B`
error[E0277]: the trait bound `example::S: example::A` is not satisfied
--> src/example.rs:11:6
|
5 | trait B: A {
| - required by this bound in `example::B`
...
11 | impl B for S {
| ^ the trait `example::A` is not implemented for `example::S`
I keep re-reading about supertraits, but I'm having trouble understanding this error.
The first error seems to contradict what trait B: A is telling the program to do.
The second error seems to contradict that the implementation of do_a(&self) {} satisfies A.
What am I missing here? Is my mental model wrong, or is my code missing some necessary boilerplate, or both?
I believe that the syntax is more about bounding the type (e.g. a type T that implements B must necessarily implement A) than inheritance in the object-oriented sense. If you write out the impls separately it compiles fine:
trait A {
fn do_a(&self);
}
trait B: A {
fn do_b(&self);
}
struct S {}
impl A for S {
fn do_a(&self) {}
}
impl B for S {
fn do_b(&self) {}
}
Playground
N.B. that if you remove the impl for A the code no longer compiles, the constraint that an impl of B must also impl A is no longer satisfied.

How can I accept a Rust HashMap with any hashing algorithm?

I'm working on a library that has a function that I would like to be able to accept a HashMap of any hashing algorithm. But when I try to call it with a particular type of HashMap, such as a FnvHashMap, the compiler complains.
pub fn func(map: HashMap<u32, u32>) {}
let map: FnvHashMap<u32, u32> = FnvHashMap::default();
func(map);
error[E0308]: mismatched types
--> lib.rs:42:10
|
42 | func(map);
| ^^^ expected struct `RandomState`, found struct `BuildHasherDefault`
|
= note: expected struct `HashMap<_, _, RandomState>`
found struct `HashMap<_, _, BuildHasherDefault<FnvHasher>>`
As FnvHashMap is only a type alias I thought this wouldn't be a problem.
I'm sure there's a way to do this, but I haven't found it yet. What's the correct way?
The definition of HashMap in the docs is:
pub struct HashMap<K, V, S = RandomState> { /* fields omitted */ }
RandomState is the default type, but it can be overridden with another type, including a generic. It may not be immediately clear, but most of the HashMap methods are declared in an impl block that constraints S: BuildHasher, which is the trait you need to bound it by:
use std::hash::BuildHasher;
pub fn func<S: BuildHasher>(map: HashMap<u32, u32, S>) {}

Why can't I push into a Vec of dyn Trait unless I use a temporary variable?

This is my code:
use std::rc::{Rc, Weak};
use std::cell::RefCell;
trait Trait {}
fn push<E: Trait>(e: E) {
let mut v: Vec<Rc<RefCell<Box<dyn Trait>>>> = Vec::new();
// let x = Rc::new(RefCell::new(Box::new(e)));
// v.push(x); // error
v.push(Rc::new(RefCell::new(Box::new(e)))); // works fine
}
The v.push(x) raises this error:
error[E0308]: mismatched types
--> src/main.rs:12:12
|
7 | fn push<E: Trait>(e: E) {
| - this type parameter
...
12 | v.push(x);
| ^ expected trait object `dyn Trait`, found type parameter `E`
|
= note: expected struct `std::rc::Rc<std::cell::RefCell<std::boxed::Box<dyn Trait>>>`
found struct `std::rc::Rc<std::cell::RefCell<std::boxed::Box<E>>>`
But if I push the value (constructed with the exact same value and types) directly into the vector it compiles without error.
So why doesn't the first version compile? And what should I change to make it so that I can use x before pushing it into the vector?
It's all in the type inference. When you write:
v.push(Rc::new(RefCell::new(Box::new(e))));
Rust can tell from that context that the argument to RefCell::new() must be a Box<dyn Trait>, so despite supplying a Box<E>, it coerces it to the former type. When you write this on the other hand:
let x = Rc::new(RefCell::new(Box::new(e)));
v.push(x); // compile error
Rust first infers that x of type Rc<RefCell<Box<E>>> and you can no longer push it into a vec of Rc<RefCell<Box<dyn Trait>>>. You can change this by putting an explicit type annotation in your let binding to tell Rust upfront that you really do want a Rc<RefCell<Box<dyn Trait>>>:
use std::rc::{Rc, Weak};
use std::cell::RefCell;
trait Trait {}
fn push<E: Trait>(e: E) {
let mut v: Vec<Rc<RefCell<Box<dyn Trait>>>> = Vec::new();
let x: Rc<RefCell<Box<dyn Trait>>> = Rc::new(RefCell::new(Box::new(e)));
v.push(x); // compiles
}
playground
The important thing to understand here is that E is not the same as dyn Trait. E is some known concrete implementation of Trait while dyn Trait is a trait object with its underlying concrete implementation erased.

Define a trait with a function that returns an associated type with the same lifetime as one parameter

I'm trying to define a trait with a function that returns an associated type with the same lifetime as one parameter.
Conceptually something like the following (which doesn't work: lifetime parameter not allowed on this type [Self::Output]):
trait Trait {
type Output;
fn get_output<'a>(&self, input: &'a i32) -> Self::Output<'a>;
}
I found several questions about lifetimes for associated types on Stack Overflow and the Internet, but none seem to help. Some suggested defining the lifetime on the whole trait:
trait Trait<'a> {
type Output;
fn get_output(&self, input: &'a i32) -> Self::Output;
}
but this doesn't work either: it compiles, but then the following function fails to compile:
fn f<'a, T>(var: &T)
where T: Trait<'a>
{
let input = 0i32;
let output = var.get_output(&input);
}
giving an error:
error: `input` does not live long enough
--> <anon>:9:35
|
| let output = var.get_output( &input );
| ^^^^^ does not live long enough
| }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the body at 7:48...
--> <anon>:7:49
|
| fn f<'a, T>( var : &T ) where T : Trait<'a> {
| _________________________________________________^ starting here...
| | let input = 0i32;
| | let output = var.get_output( &input );
| | }
| |_^ ...ending here
How should I define the trait so that it behaves the way I want?
This is currently impossible, even in nightly Rust.
This requires some form of Higher Kinded Types (HKT), and the current approach envisaged is dubbed Associated Type Constructor (ATC).
The main motivation for introducing ATC is actually this very usecase.
With ATC, the syntax would be:
trait Trait {
type Output<'a>;
fn get_output<'a>(&self, input: &'a i32) -> Self::Output<'a>;
}
Note: if you wish to learn about ATCs, see Niko's series of articles.
For the particular example you have, you can work around this with HRTB (Higher Ranked Traits Bounds) as noted by Shepmaster:
fn f<T>(var: &T)
where for<'a> T: Trait<'a>
{ ... }
however this is fairly limited (notably, limited to trait bounds).
This requires using higher-ranked trait bounds:
fn f<T>(var: &T)
where for<'a> T: Trait<'a>
{
let input = 0i32;
let output = var.get_output(&input);
}
See also:
How does for<> syntax differ from a regular lifetime bound?

Resources