Using impl Trait return values?


#1

After reading the 1.26 release blog post I thought I’d give impl Trait a go. While the blog post shows using impl Trait in function declarations, it doesn’t actually show any code making use of those functions.

I was hoping that I’d be able to annotate the variable ray in the first line of main() with the trait name either like:

let ray: impl Ray = ray();

or:

let ray: Ray = ray();

For clarity’s sake. In cases where you’re using a 3rd party API and don’t have the definition of the function right in your code, what’s written at the call site could end up being quite obscure. Is this really how impl Trait return values are expected to be used?

struct Light {}

trait Ray {
    fn shine(&self) -> u32;
}

impl Ray for Light {
    fn shine(&self)-> u32 {
        299_792_458u32
    }
}

fn ray() -> impl Ray {
    return Light {}
}

fn main() {
    let ray = ray();
    println!("ray.shine(): {:?}!", ray.shine());
}

Permalink to the playground


#2

For now yes, the extension of impl Trait to let declarations has been RFCed, but it’s not yet implemented.


#3

That’s good news, thanks!


#4

The same no annotation applies to closures. To store in a structure use a generic.
At the moment if you want annotation you have to take the hit of box and dynamic dispatch.

let ray: Box<dyn Ray> = Box::new(ray());

p.s. dyn is coming in 1.27 (Is just text added to language to make trait objects more newcomer/reader friendly.)


#5

That’s interesting, I wasn’t aware of dyn. Do you know of any blog posts about dyn or where I can learn more about it besides a Github issue thread? They’re a little too verbose.


#6

None other that I know of. It will be in the 1.27 release blog when it arrives. It is only (from user point) just textual change, with warnings when you don’t use it, so not as big a deal as impl Trait. My personal view ATM is; it is probably worth the verbose hit.


#7

Curious what a strong argument for dyn is. This is another change that appears to be beginner oriented but I’m having a hard time accepting as meaningfully useful. Is there really confusion about what’s a trait object once a person gains a bit of familiarity with them?


#8

Mainly at beginner but also makes explicit &Identifier has Identifier as concrete data type without having to look. It is replacing the old syntax; unlike argument impl Trait, which adds another form to what can be written with generic (or +where)


#9

https://rust-lang-nursery.github.io/edition-guide/2018/transitioning/traits/dyn-trait.html are the current docs for dyn Trait, https://github.com/rust-lang/book/issues/1277 is the book tracking issue.


#10

Personally, I find it very helpful, even knowing trait objects, to have the marker that turns something from a trait to a type, to make the distinction visible. Combined with impl, I like having the three options: Foo<Bar> (taking a specific-and-visible type), Foo<dyn Bar> (taking a dynamic type), and Foo<impl Bar> (taking a specific-but-hidden type).


#11

Why is it important to see the distinction? To know (outside of an IDE, say) that you have dynamic dispatch?