Returning Types & impl Trait

Hi

I may have missed something, but I recently got stuck with a question:

The code (modified from rust-by-example):

struct Sheep { naked: bool, name: &'static str }

trait Animal {
    fn new(name: &'static str) -> Self; 
    fn name(&self) -> &'static str;
} 

impl Animal for Sheep {
    fn new(name: &'static str) -> Sheep {
        Sheep { name: name, naked: false }
    } 

    fn name(&self) -> &'static str {
        self.name
    }
} 

fn main() {

    let dolly = Sheep::new("Dolly");
    println!("{}", dolly.name); // It's OK 

    let molly = bounded_return("Molly");
    println!("{}", molly.name); // It produces an Error
    //                   ^attempted to take value
    //                    of method `name` on type `impl Animal`
    //                    method, not a field!
    println!("{}", molly.name()); // It's OK
    //
    //         OR the same with Type annotation
    //
    let molly: Sheep = bounded_return("Molly"); // It produces an Error
    //                 ^mismatched types
    //                  expected struct `Sheep`
    //                  found opaque type `impl Animal`
} 

fn bounded_return(x: &'static str) -> impl Animal {
    Sheep {
        name: x,
        naked: false,
    }
}

Having instantiated struct Sheep with the bounded_return function, I then cannot access the value of name field of the instance. It's only possible to get the value as self.name via the name function, declared in the Animal trait.

So, do I understand it right?:

  • If a value of some type is returned from a function with impl Trait syntax in the return position of its signature, that returned value is never just a value "of some type that implements the Trait", but instead a value of the type impl Trait;

  • impl Trait is a so called "opaque type" that only makes it possible to access a specific set of methods defined when that Trait was implemented on a type, and nothing apart from those methods (that's why molly.name, which isn't an Animal method, does not work but 'molly.name()' does);

  • The code, calling functions with impl Trait return type never knows about the "real, behind the scenes" type (Sheep), which is hence called "hidden", but yet can infer it (in the given code, from the body of the bounded_return function).

    • It is somewhat similar to using let dolly: Sheep = Animal::new("Dolly"); instead of let dolly = Sheep::new("Dolly"); for instantiating Sheep.

And one more question:

  • were these "opaque" and "hidden" types introduced by design or are just an unintentional by-prodict of impl Trait syntax?

No, the point is exactly that impl Trait is not a type. Return-position impl Trait syntax means "I'm returning a concrete type, but you are not allowed to know what it is, only what trait it implements".

Right.

The point of impl Trait is exactly that it's opaque. It frees the author of the function from having to commit to a specific type. It is very intentional.

4 Likes

Thank you!

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.