How can I get around this issue?

I have the following signature on a trait:

    fn init<T>(&mut self, symbols: Vec<String>) -> Result<std::thread::JoinHandle<T>, String>;

This results in

| ----------------- this trait cannot be made into an object...

10 | fn init(&mut self, symbols: Vec) -> Result<std::thread::JoinHandle, String>;

| ^^^^ ...because method init has generic type parameters

and I can't use underscore either or I get

error[E0121]****: the placeholder _ is not allowed within types on item signatures for functions

I'm worried there is no good workaround for this (yes, I do need a trait object here).

(In search of some XY that may lead to as solution or workaround...)

If the caller chooses the T, and there are no further restrictions, where does the FnOnce() -> T that was required to create the JoinHandle<T> come from?

To more directly address the question, you have to get rid of the type generic on the method. Sometimes this is possible by type-erasing the generic, e.g.

trait Trait {
    // fn method<T: Debug>(&self, _: T);
    fn method(&self, _: &dyn Debug);
}

Good thinking.

Unless I missed it, the docs don't even tell us what that type param is. If I had to make a WAG, I'd say it was the type of the return value of the thread - if there is such a thing.

Anyway, I simply tried

JoinHandle<String>

and it compiled and worked, to my surprise.

It's whatever the closure you pass to spawn returns.

From the docs:

As you can see in the signature of spawn there are two constraints on both the closure given to spawn and its return value, let’s explain them:

  • The 'static constraint means that the closure and its return value must have a lifetime of the whole program execution. The reason for this is that threads can outlive the lifetime they have been created in.Indeed if the thread, and by extension its return value, can outlive their caller, we need to make sure that they will be valid afterwards, and since we can’t know when it will return we need to have them valid as long as possible, that is until the end of the program, hence the 'static lifetime.
  • The Send constraint is because the closure will need to be passed by value from the thread where it is spawned to the new thread. Its return value will need to be passed from the new thread to the thread where it is joined. As a reminder, the Send marker trait expresses that it is safe to be passed from thread to thread. Sync expresses that it is safe to have a reference be passed from thread to thread.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.