Returning different types in a match

I presume if you return a boxes dyn trait you could make the function return an impl trait so that you could change the implementation in future?

When you say impl Trait, like here:

fn b() -> impl Trait

it desugars to be a concrete type that is chosen by the function caller itself, so in other words:

fn b<T: Trait>() -> T

and, this reveals the problem because it now looks closer to generics (It is generics) and you can't return different types depending on the code inside the function b because it'd be determined at runtime and (I'm not too sure if this fits the right terminology) would have to be evaluated dynamically, and generics are something evaluated at compile-time, and not runtime therefore requiring a Trait Object.

1 Like

No, the "underlying" return type of an impl Trait returning function is callee chosen, unlike your second example which allows the caller to choose the return type every time they call the function (c.f Iterator::collect). That's the reason for having a separate impl Trait mechanism. However, you're right that it is a single concrete type, so all return values have to be the same type.

2 Likes

Wow, I really messed up that one, I was so focused on adding the bold formatting that I forgot to think about the point, so yes, it's chosen by the function itself and not the caller

2 Likes

Would appreciate people not replying to posts inactive for a year. Thanks

@dylan.dpc - You chose an excellent title that makes it easy for others stuck on the same problem to find help. It helped me at least :slight_smile: I apologize if you were surprised by the notification, and totally get how that can be an unexpected annoyance - but imho it's better to collect the knowledge on this topic here rather than start another post with nearly the same exact question - and it turns out that the state of the art here has not changed that much in a year. At the same time, for sure it's a subjective preference... I get it.

Fwiw I tried tinkering around with impl Trait returns and, as explained by everyone above, couldn't make it work. Dynamic dispatch it is! Here's a working example:

(outputs both "foo" and "bar")

use std::fmt::{Display, Formatter, Result};

struct Foo {}
struct Bar {}

impl Display for Foo {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "foo")
    }
}

impl Display for Bar {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "bar")
    }
}

fn get_something (name:&str) -> Option<Box<dyn Display>> {
    match name {
        "foo" => Some(Box::new(Foo{})),
        "bar" => Some(Box::new(Bar{})),
        _ => None
    }
}
fn main() {
    println!("{}", get_something("foo").unwrap());
    println!("{}", get_something("bar").unwrap());
}

It turns out the dyn keyword isn't needed.... is that inferred somehow?

dyn keyword is needed. It isn't a hard error yet if you don't use it (but could be in future).

Oh interesting... maybe it should at least be a warning then?

1 Like

Haha, sorry for the bother, but you can choose to not be notified unless your name is mentioned, just a tip

Yes i'm aware of that. Just that you have to change it on every thread you create.