Provided method casting &self to trait object - rust

I have a trait in which I want to provide a method. The method is to be implemented in terms of some helpers that have no business being inside the trait and are non-trivial enough that dynamic polymorphism makes more sense than making them generic. So I have code along the lines of
fn use_trait(x: &Trait) {
println!("object says {}", x.needed());
}
trait Trait {
fn needed(&self) -> &str;
fn provided(&self) {
use_trait(self);
}
}
struct Struct();
impl Trait for Struct {
fn needed(&self) -> &str {
"Hello, world!"
}
}
fn main() {
Struct().provided();
}
Which, however, does not compile, with error:
error[E0277]: the trait bound `Self: std::marker::Sized` is not satisfied
--> <anon>:9:19
|
9 | use_trait(self);
| ^^^^ the trait `std::marker::Sized` is not implemented for `Self`
|
= help: consider adding a `where Self: std::marker::Sized` bound
= note: required for the cast to the object type `Trait`
I understand why—it is not guaranteed somebody won't implement the trait for an unsized type (converting from &T where T: Trait to &Trait requires T: Sized, but the declaration does not require that).
However, the advice will not do what I need. I can add
fn needed(&self) -> &str where Self: Sized
but then the needed() method won't be accessible on &Trait (because Trait : ?Sized), which renders the thing useless, because the type (the actual one that does something useful) is always handled as Arc<Trait>. And adding
trait Trait: Sized
is even worse, because that does not permit &Trait at all (Trait as a type is unsized, so Trait type does not implement trait Trait).
Of course I can simply make
fn use_trait<T: Trait>(x: &T)
but there is a lot behind it in the real code, so I don't want monomorphisation there especially since the trait is otherwise always handled as trait object.
Is there any way to tell Rust that all types that impl Trait must be sized and here is a definition of a method that should work for all of them?

You need an additional as_trait function on Trait and its implementations:
trait Trait {
fn needed(&self) -> &str;
fn provided(&self) {
use_trait(self.as_trait());
}
fn as_trait(&self) -> &Trait;
}
struct Struct();
impl Trait for Struct {
fn needed(&self) -> &str {
"Hello, world!"
}
fn as_trait(&self) -> &Trait {
self as &Trait
}
}
You can try it on the playground. (trait objects)

Enhanced version of #JoshuaEntrekin's answer:
The helper as_trait function can be put in an auxiliary trait that gets blanket implementation for all Sized types trying to implement Trait. Then the implementer of Trait does not have to do anything special and the conversion works.
fn use_trait(x: &Trait) {
println!("object says {}", x.needed());
}
trait Trait : AsTrait {
fn needed(&self) -> &str;
fn provided(&self) where Self : AsTrait {
use_trait(self.as_trait());
}
}
trait AsTrait {
fn as_trait(&self) -> &Trait;
}
impl<T : Trait + Sized> AsTrait for T {
fn as_trait(&self) -> &Trait { self }
}
struct Struct();
impl Trait for Struct {
fn needed(&self) -> &str {
"Hello, world!"
}
}
fn main() {
Struct().provided();
}
(on play).
It would also be possible to simply put provided in the auxiliary trait, but then it would have to dynamically dispatch to the other methods of Self unnecessarily.
Update: Actually, the point is that it should still be possible to override provided.
Now the above can be improved further by making it generic. There is std::makrer::Unsize, which is unstable at the time of this writing. We can't make
trait Trait : Unsize<Trait>
because Rust does not allow CRTP, but fortunately it is enough to put the constraint on the method. So
fn use_trait(x: &Trait) {
println!("object says {}", x.needed());
}
trait Trait {
fn needed(&self) -> &str;
fn provided(&self) where Self: AsObj<Trait> {
use_trait(self.as_obj());
}
}
trait AsObj<Tr: ?Sized> {
fn as_obj(&self) -> &Trait;
}
// For &'a Type for Sized Type
impl<Type: Trait> AsObj<Trait> for Type {
fn as_obj(&self) -> &Trait { self }
}
// For trait objects
impl AsObj<Trait> for Trait {
fn as_obj(&self) -> &Trait { self }
}
struct Struct();
impl Trait for Struct {
fn needed(&self) -> &str {
"Hello, world!"
}
fn provided(&self) {
println!("Aber dieses Objekt sagt Grüß Gott, Welt!"); // pardon my German, it is rusty.
}
}
fn main() {
let s: &Trait = &Struct();
s.provided();
}
(on play)
This finally makes it transparent for the implementors of other versions.
See also this users thread.

Related

Implement methods for trait without additional traits

Looking for "blanket" implementation of the method(s) for trait.
Let's say for a trait
pub trait A {
fn do_a(&self);
}
want to have boxed method that wraps with box, without introducing any additional traits:
fn boxed(self) -> Box<Self>;
I can have another trait to achieve that (playground)
pub trait A {
fn do_a(&self);
}
pub trait Boxed {
fn boxed(self) -> Box<Self>;
}
impl<T> Boxed for T
where
T: A,
{
fn boxed(self) -> Box<Self> {
Box::new(self)
}
}
However, new trait Boxed is required for that.
You can add boxed directly to A with a default implementation so that structs won't need to implement it themselves:
trait A {
fn do_a(&self);
fn boxed (self) -> Box<Self>
where Self: Sized
{
Box::new (self)
}
}
struct Foo{}
impl A for Foo {
fn do_a (&self) {
todo!();
}
// No need to redefine `boxed` here
}
fn main() {
let foo = Foo{};
let _object: Box<dyn A> = foo.boxed();
}
Playground

Passing boxed trait object to function accepting generic parameter implementing the trait

I have a function which returns a boxed trait object, and another function that accepts a reference to an object implementing the same trait. I would like to pass a reference to the boxed trait object to the second function, but I am unable to figure out how to do this.
Example simplified code:
trait MyTrait {
fn foo(&self);
}
struct A {}
impl MyTrait for A {
fn foo(&self) {
println!("A");
}
}
struct B {}
impl MyTrait for B{
fn foo(&self) {
println!("B");
}
}
enum MyEnum {
A,
B,
}
fn create_object(my_enum: MyEnum) -> Box<dyn MyTrait> {
let boxed_value: Box<dyn MyTrait> = match my_enum {
MyEnum::A => Box::new(A{}),
MyEnum::B => Box::new(B{}),
};
boxed_value
}
fn do_something<T: MyTrait>(obj: &T) {
obj.foo();
}
fn main() {
use std::borrow::BorrowMut;
let boxed_value = create_object(MyEnum::A);
do_something(boxed_value.borrow_mut());
}
The error I get:
error[E0282]: type annotations needed
--> src\main.rs:42:5
|
42 | do_something(boxed_value.borrow_mut());
| ^^^^^^^^^^^^ ------------------------ this method call resolves to `&mut Borrowed`
| |
| cannot infer type for type parameter `T` declared on the function `do_something`
Intuitively, I would have hoped that in this case Rust would use dynamic dispatch and wouldn't care about the concrete type T (similarly to what happens in C++ when you pass a reference to a base class), but this seems not to be the case.
How do I pass a reference to the boxed trait object (Box<dyn MyTrait>) to the second function (do_something)? Is this possible in some way? A solution requiring a change to do_something would also be acceptable.
Intuitively, I would have hoped that in this case Rust would use dynamic dispatch and wouldn't care about the concrete type T (similarly to what happens in C++ when you pass a reference to a base class), but this seems not to be the case.
You can make that happen with a cast (or just type ascription, eventually) and by relaxing the default requirement for T to be Sized:
fn do_something<T: MyTrait + ?Sized>(obj: &T) {
obj.foo();
}
use std::borrow::Borrow;
let boxed_value = create_object(MyEnum::A);
do_something(boxed_value.borrow() as &dyn MyTrait);
But if you’re not otherwise using T, you can opt into dynamic dispatch on the function side much more simply:
fn do_something(obj: &dyn Borrow) {
obj.foo();
}
use std::borrow::Borrow;
let boxed_value = create_object(MyEnum::A);
do_something(boxed_value.borrow());
And if you don’t care that obj is a borrow and want to leave the option of static dispatch open, you can implement MyTrait for &dyn MyTrait:
impl MyTrait for &dyn MyTrait {
fn foo(&self) {
(*self).foo();
}
}
fn do_something<T: MyTrait>(obj: T) {
obj.foo();
}
// or, again, if not otherwise using T:
fn do_something(obj: impl MyTrait) {
obj.foo();
}
use std::borrow::Borrow;
let boxed_value = create_object(MyEnum::A);
do_something(boxed_value.borrow());
No matter what, you'll need to add ?Sized to the trait bound in do_something, and then I think you have one of three options:
(Least general) Use as_ref() on the Box when you call do_something.
fn do_something<T: MyTrait + ?Sized>(obj: &T) {
obj.foo();
}
fn main() {
let boxed_value = create_object(MyEnum::A);
do_something(boxed_value.as_ref());
}
(Most general) Replace the type of obj in do_something with impl AsRef<T>. This will make do_something work with anything convertible to a &T.
fn do_something<T: MyTrait + ?Sized>(obj: impl AsRef<T>) {
obj.as_ref().foo();
}
fn main() {
let boxed_value = create_object(MyEnum::A);
do_something(boxed_value);
}
(Medium general) Replace the type of obj in do_something with impl Deref<Target=T>. This will make do_something work with any smart pointer holding a T (which is a bit more restrictive than AsRef<T> — a type can implement AsRef<T> for as many values of T as it wants, but only gets to have one Deref implementation).
use std::ops::Deref;
fn do_something<T: MyTrait + ?Sized>(obj: impl Deref<Target=T>) {
obj.deref().foo();
}
fn main() {
let boxed_value = create_object(MyEnum::A);
do_something(boxed_value);
}
Instead of trying to unbox the value
you can instead implement MyTrait on Box<dyn MyTrait>
and forward to the boxed value.
impl MyTrait for Box<dyn MyTrait> {
fn foo(&self) {
self.deref().foo()
}
}
Then you don't even need to call borrow_mut.
fn main() {
use std::borrow::BorrowMut;
let boxed_value = create_object(MyEnum::A);
do_something(&boxed_value);
}
There's a working example in the playground

`AsArray` cannot be made into an object when implementing a trait for a trait

Basically I'm trying to make a trait that indicates the ability to be converted into a 2D ndarray aka ndarray::Array2:
trait Into2DArray{
fn to_array(&self) -> Array2<f64>;
}
I would like to do this by expanding the existing AsArray trait, but Rust forbids me from implementing a third party trait for a third party struct (polars::DataFrame) for some esoteric reason, so instead I have to make my own trait for this.
Anyway, this works well for polars::DataFrame:
impl Into2DArray for DataFrame {
fn to_array(&self) -> Array2<f64> {
return self.to_array();
}
}
However, I also want to implement this for anything that is already convertable into a 2D array, so I implement this trait for the AsArray trait mentioned above:
impl Into2DArray for AsArray<'_, f64, Ix2> {
fn to_array(&self) -> Array2<f64> {
return self.into();
}
}
However the compiler gives me grief for this:
|
26 | impl Into2DArray for AsArray<'_, f64, Ix2> {
| ^^^^^^^^^^^^^^^^^^^^^ `AsArray` cannot be made into an object
|
= note: the trait cannot be made into an object because it requires `Self: Sized`
= 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>
I understand that has something to do with object safety but I thought I had fulfilled all the criteria mentioned on that page, namely the trait doesn't return Self, and all the generic parameters of AsArray are specified.
What is going wrong, and how can I fix it?
What you were trying to do is implementing the Into2DArray trait for the AsArray dynamic trait object. There should have been a warning of using AsArray without dyn anyway.
But this is not what you actually want. You want to implement it for any type that implements AsArray. Just like you did in your comment.
It is important to know the difference between these two things:
trait NeedThis {
fn can_be_called_by_the_impl(&self) {}
}
trait ToDoThis {
fn example(&self);
}
impl ToDoThis for dyn NeedThis {
fn example(&self) {
self.can_be_called_by_the_impl()
}
}
impl NeedThis for u8 {}
fn main() {
let num: u8 = 0;
// num.example(); // doesn't work because ToDoThis is not implemented for u8
let num_as_trait_obj: &dyn NeedThis = &0_u8 as &dyn NeedThis;
num_as_trait_obj.example(); // works because this time it is a trait object
}
trait NeedThis {
fn can_be_called_by_the_impl(&self) {}
}
trait ToDoThis {
fn example(&self);
}
// removing ?Sized would make it the same as T: NeedThis + Sized
impl<T: NeedThis + ?Sized> ToDoThis for T {
fn example(&self) {
self.can_be_called_by_the_impl()
}
}
impl NeedThis for u8 {}
fn main() {
let num: u8 = 0_u8;
num.example(); // works because we implemented it for all types that implement NeedThis
let num_as_trait_obj: &dyn NeedThis = &0_u8 as &dyn NeedThis;
num_as_trait_obj.example(); // works because dyn NeedThis also implements NeedThis.
// This is only true because we added ?Sized to the bounds of the impl block.
// Otherwise it doesn't work because dyn NeedThis is not actually Sized.
// And a Sized bound is implied by default.
}

How can I specify `Sized` for boxed value

I want to notify that "this method will return boxed Struct which implements Trait and Sized".
Simple resolution is just put Struct into Box but I can't because Struct has so big generic parameter that I can't write manually.
// I can't edit these trait and struct.
trait Trait {}
struct Struct();
impl Trait for Struct {}
// This is my code.
fn func() -> Box<Trait> {
Box::new(Struct{})
}
// This is not my code.
fn need_sized<T: Trait + Sized>(item: T) {
println!("ok");
}
fn main() {
// This can not be compiled!
need_sized(func());
}
I can edit func function but I can't others.
How can I specify that Trait implements Sized?
Is it something kind like below?
fn func() -> Box<Trait + Sized>
Given the specification the only way you can bypass this is to make newtype wrapper.
// I can't edit these trait and struct.
trait Trait {}
struct Struct();
impl Trait for Struct {}
// This is my code.
struct MyStruct(Struct);
impl Trait for Box<MyStruct> { /* if there is code here delegate to inner `Struct` */}
fn func() -> Box<MyStruct> {
Box::new(MyStruct(Struct{}))
}
// This is not my code.
fn need_sized<T: Trait + Sized>(item: T) {
println!("ok");
}
fn main() {
// This can not be compiled!
need_sized(func());
}
playground
Why other approaches won't solve your issues:
Monomorphisized trait
fn func<T: Trait>() -> Box<T> { ... }
You want to pass func to need_size. More specifically, you want to pass Box to the need_size function.
Changing function signature to Box<Struct>
error[E0277]: the trait bound std::boxed::Box<Struct>: Trait is not satisfied
--> <anon>:22:5
|
22| need_sized(func());
| ^^^^^^^^^^ the trait `Trait` is not implemented for `std::boxed::Box<Struct>`
|= help: the following implementations were found:
<std::boxed::Box<MyStruct> as Trait>
= note: required by `need_sized`
This won't work because you can't control either Box or Struct since they aren't defined in you crate, and it would mess up with coherence rules. In future this might be solved using special coherence rules.
I think you need to be able to change either func or need_sized for this to work. As they are, func returns a trait object which is unsized, while need_sized requires a concrete type (more than that, it requires full ownership of its parameter item, not just a reference).
Approach 1: if you control and can change func(), you can change it to return a Box<Struct> instead of Box<Trait>:
fn func() -> Box<Struct> {
Box::new(Struct{})
}
fn main() {
let s1 = func(); // Box<Struct>, needs dereferencing with *
// to become a Struct
need_sized(*s1); // this now works
}
Approach 2: if you don't control func() but do control need_sized and Trait you can downcast the Box back to a Struct as in this answer: https://stackoverflow.com/a/33687996/497364
playground
use std::any::Any; // needed for downcast
trait Trait {
fn as_any(&self) -> &Any;
}
struct Struct{}
impl Trait for Struct {
fn as_any(&self) -> &Any {
self
}
}
fn func() -> Box<Trait> {
Box::new(Struct{})
}
// changed to accept a &T
fn need_sized<T: Trait + Sized>(_item: &T) {
println!("ok");
}
fn main() {
let s2 = func();
if let Some(st) = s2.as_any().downcast_ref::<Struct>() {
need_sized(st);
}
}
The error message is;
error[E0277]: the trait bound std::boxed::Box<Trait>: Trait is not satisfied
So adding;
impl Trait for Box<Trait> {}
after line three lets it compile.

Create a generic struct with Option<T> without specifying T when instantiating with None

I have a
struct Foo<T>
where
T: // ... some complex trait bound ...
{
a: Bar,
b: Option<T>,
}
When attempting to instantiate the struct with a b: None the compiler complains that it cannot infer the type and requires a type hint e.g. via the turbofish syntax. That is onerous on the caller because they will have to find a type that fulfills the trait bounds and import it despite not caring about that optional functionality.
I think what I am looking for would be a bottom type that automatically fulfills any trait bounds but cannot be instantiated so that None::<Bottom> could be used, but I have not found such a type in the documentation.
There's a feature in the works that allows specifying the never type as !. This is not present in stable Rust, so you need to use a nightly and a feature flag:
#![feature(never_type)]
fn thing<T>() -> Option<T> {
None
}
fn main() {
thing::<!>();
}
However, this doesn't work for your case yet (this is part of the reason that it's unstable):
#![feature(never_type)]
trait NothingImplementsMe {}
fn thing<T>() -> Option<T>
where T: NothingImplementsMe,
{
None
}
fn main() {
thing::<!>();
}
error[E0277]: the trait bound `!: NothingImplementsMe` is not satisfied
--> src/main.rs:12:5
|
12 | thing::<!>();
| ^^^^^^^^^^ the trait `NothingImplementsMe` is not implemented for `!`
|
= note: required by `thing`
The very first unresolved question on the tracking issue is:
What traits should we implement for !?
Since this feature is both unstable and doesn't do what you want, you may want to consider creating your own bespoke "bottom" type:
trait AlmostNothingImplementsMe {
fn foo();
}
struct Nope;
impl AlmostNothingImplementsMe for Nope {
fn foo() { unimplemented!() }
}
fn thing<T>() -> Option<T>
where T: AlmostNothingImplementsMe,
{
None
}
fn main() {
thing::<Nope>();
}
To improve the UX of this, I'd suggest creating a builder of some type that starts you off with the faux-bottom type:
mod nested {
pub trait AlmostNothingImplementsMe {
fn foo();
}
pub struct Nope;
impl AlmostNothingImplementsMe for Nope {
fn foo() { unimplemented!() }
}
pub fn with_value<T>(t: T) -> Option<T>
where T: AlmostNothingImplementsMe,
{
Some(t)
}
pub fn without_value() -> Option<Nope> {
None
}
}
fn main() {
nested::without_value();
}
You can see this similar pattern in crates like Hyper, although it boxes the concrete type so you don't see it from the outside.
One option to avoid the need to the turbofish operator is to have a type alias:
trait MyTrait {}
impl MyTrait for () {}
struct Foo<T: MyTrait> {
i: isize,
o: Option<T>,
}
type Bar = Foo<()>;
fn main() {
let foo_default = Bar { i: 1, o: None };
}
I used () as the default for simplicity, but ! (when available) or your own bottom type as in #Shepmaster's answer may be better.
A constructor function could also work if you don't mind Foo::new_default(i) or similar.

Resources