3

As the following code shows:

  trait T2impl {}

  struct S4T2impl;

  impl T2impl for S4T2impl{}

  trait TimplMethod {
   fn f() -> impl T2impl;
  }

  struct S4TimplMethod;

  impl TimplMethod for S4TimplMethod {
   fn f() -> impl T2impl {
    S4T2impl
   }
  }

  fn f1() -> impl TimplMethod {
   S4TimplMethod
  }
 
  // so far so good
  // but I want to return one of more TimplMethod implementations, so I need a dynamic approach:

  // fn f2() -> Box<dyn TimplMethod> {
  //  Box::new( S4TimplMethod)
  // }

Here I get the error message:

error[E0038]: the trait `TimplMethod` cannot be made into an object
   --> src/main.rs:158:18
    |
158 |   fn f2() -> Box<dyn TimplMethod> {
    |                  ^^^^^^^^^^^^^^^ `TimplMethod` 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:140:7

How can I solve this problem?

[update]

As I can see in some answers some suggest to change the TimplMethod trait. This is not what I am looking for. Please consider all code from line 1 to function f1 as read-only.

3
  • Return Box<dyn T2impl> instead of impl T2impl from the method. Commented Jan 8, 2024 at 12:24
  • This don't solve the problem because is is an example and it can be that I am not able to change the associated method TimplMethod::f . Commented Jan 8, 2024 at 12:31
  • You can create an adapter trait that will be the same as TimplMethod except its f() will return Box<dyn T2impl>. The question is, will it be enough for you? Commented Jan 8, 2024 at 12:32

1 Answer 1

1

If you can't change TimplMethod, you can create an object-safe helper trait that is defined for all types that define TimplMethod, and return that:

// TimplMethod and its implementers unchanged

// helper trait that provides a boxed T2impl in its f()
trait TimplMethodErased {
    fn f(&self) -> Box<dyn T2impl + '_>;
}

// blanket implementation for the helper trait for every type
// that implements the original
impl<T> TimplMethodErased for T
where
    T: TimplMethod,
{
    fn f(&self) -> Box<dyn T2impl + '_> {
        Box::new(T::f())
    }
}

fn f1() -> Box<dyn TimplMethodErased> {
    Box::new(S4TimplMethod)
}

Playground

Sign up to request clarification or add additional context in comments.

5 Comments

The next step is to impl TimplMethod for dyn TimplMethodErased.
@ChayimFriedman Thanks for the suggestion, but what would TimplMethod::f() look like in such an impl? There is no self to dispatch on.
It will just call TimplMethodErased::f(). Assuming Box<dyn T2impl> implements T2Impl, this should be enough.
@ChayimFriedman The problem is that TimplMethodErased::f() requires self, and has to in order to be object-safe. There is no self in TimplMethod::f().
Ah, right. Then you cannot do that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.