Search code examples
rusttraitsrust-proc-macros

How to call an inherited method from trait in Rust


pub mod stuff {
    pub trait Clone2: Clone {}
    
    impl<T: Clone> Clone2 for Vec<T> {}
}

fn main() {
    let x: Vec<u32> = Default::default();
    let _ = stuff::Clone2::clone(&x);
}

I would like to call the .clone() method of Clone but from the trait Clone2 but for some reason it doesn't compile. There are some caveats:

  1. I don't want to do simply x.clone() because I won't necessarily have Clone2 in scope (nor event Clone).
  2. I don't want to use Clone::clone(&x) because I need to ensure that the type actually implements Clone2.

Here is a playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=2657776369da56fded5b62f5bad16d4d

   Compiling playground v0.0.1 (/playground)
error[E0782]: trait objects must include the `dyn` keyword
 --> src/main.rs:9:13
  |
9 |     let _ = stuff::Clone2::clone(&x);
  |             ^^^^^^^^^^^^^
  |
help: add `dyn` keyword before this trait
  |
9 |     let _ = <dyn stuff::Clone2>::clone(&x);
  |             ++++              +

error[E0038]: the trait `Clone2` cannot be made into an object
 --> src/main.rs:9:34
  |
9 |     let _ = stuff::Clone2::clone(&x);
  |                                  ^^ `Clone2` cannot be made into an object
  |
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
 --> src/main.rs:2:23
  |
2 |     pub trait Clone2: Clone {}
  |               ------  ^^^^^ ...because it requires `Self: Sized`
  |               |
  |               this trait cannot be made into an object...
  = note: required for the cast from `&Vec<u32>` to `&dyn Clone2`

error[E0277]: the size for values of type `dyn Clone2` cannot be known at compilation time
 --> src/main.rs:9:34
  |
9 |     let _ = stuff::Clone2::clone(&x);
  |             -------------------- ^^ doesn't have a size known at compile-time
  |             |
  |             required by a bound introduced by this call
  |
  = help: the trait `Sized` is not implemented for `dyn Clone2`
note: required by a bound in `clone`
 --> /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/core/src/clone.rs:160:5

error[E0038]: the trait `Clone2` cannot be made into an object
 --> src/main.rs:9:13
  |
9 |     let _ = stuff::Clone2::clone(&x);
  |             ^^^^^^^^^^^^^ `Clone2` cannot be made into an object
  |
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
 --> src/main.rs:2:23
  |
2 |     pub trait Clone2: Clone {}
  |               ------  ^^^^^ ...because it requires `Self: Sized`
  |               |
  |               this trait cannot be made into an object...

error[E0038]: the trait `Clone2` cannot be made into an object
 --> src/main.rs:9:13
  |
9 |     let _ = stuff::Clone2::clone(&x);
  |             ^^^^^^^^^^^^^^^^^^^^^^^^ `Clone2` cannot be made into an object
  |
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
 --> src/main.rs:2:23
  |
2 |     pub trait Clone2: Clone {}
  |               ------  ^^^^^ ...because it requires `Self: Sized`
  |               |
  |               this trait cannot be made into an object...

error[E0746]: return type cannot have an unboxed trait object
 --> src/main.rs:9:13
  |
9 |     let _ = stuff::Clone2::clone(&x);
  |             ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
  |
help: box the return type, and wrap all of the returned values in `Box::new`
  |
9 |     let _ = Box<stuff::Clone2::clone>(&x);
  |             ++++                    +

Some errors have detailed explanations: E0038, E0277, E0746, E0782.
For more information about an error, try `rustc --explain E0038`.
error: could not compile `playground` (bin "playground") due to 6 previous errors

Right now the only way I found that works is this:

pub mod stuff {
    pub trait Clone2: Clone {}
    
    impl<T: Clone> Clone2 for Vec<T> {}
}

fn main() {
    let x: Vec<u32> = Default::default();
    
    fn clone2_clone<T: stuff::Clone2>(x: &T) -> T {
        x.clone()
    }
    
    let _ = clone2_clone(&x);
}

This is okayish but I really wish to do that without defining a new function.


Solution

  • In the end I think the best solution I found is to copy (no pun intended) what they did with core::mem::copy() for the trait Copy.

    https://doc.rust-lang.org/std/mem/fn.copy.html

    Bitwise-copies a value.

    This function is not magic; it is literally defined as

    pub fn copy<T: Copy>(x: &T) -> T { *x }
    

    It is useful when you want to pass a function pointer to a combinator, rather than defining a new closure.

    Example:

    #![feature(mem_copy_fn)]
    use core::mem::copy;
    let result_from_ffi_function: Result<(), &i32> = Err(&1);
    let result_copied: Result<(), i32> = result_from_ffi_function.map_err(copy);
    

    Since I'm using a trait, I have put the function inside the trait as "provided method":

    pub mod stuff {
        pub trait Clone2: Clone {
            fn clone2(&self) -> Self {
                Clone::clone(self)
            }
        }
            
        impl<T: Clone> Clone2 for Vec<T> {}
    }
    
    fn main() {
        let x: Vec<u32> = Default::default();
        stuff::Clone2::clone2(&x);
    }
    

    Playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=7ed949c36bc6cc98471835e38f8b2f61