How to make a function which is callable for &Foo and for <F : Foo>

Is there a reason why this code doesn’t work?

trait Foo: 'static {
    fn core_functionality(&self);
}

impl Foo {
    fn utility_shortcut(&self) {
        self.core_functionality();
    }
}

// this works
fn f1(foo: &Foo) {
    foo.utility_shortcut();
}

fn f2<F: Foo>(foo: F) {
    // this doesn't work
    // foo.utility_shortcut();
    // this works, but requires casting
    (&foo as &Foo).utility_shortcut();
}

(play)

I’d like utility_shortcut function to be callable on &Foo and on type F which implements Foo, and I cannot think of a way how to do it.

(I cannot add utility_shortcut directly to Foo trait, because it increases generated code size: it would be added to each Foo implementation, which is problematic in certain situations).

impl Foo {
    fn utility_shortcut(&self) {
        self.core_functionality();
    }
}

This makes the method available only on Foo trait objects, and that requires you to coerce to one in f2.

I can see a couple of approaches:

  1. Make utility_shortcut a free function that takes a &Foo trait object.
  2. Create a separate trait, let’s call it FooExt, that contains the util method. Then impl it for Foo and for F: Foo

This is one of those situations where I strongly encourage you to use dyn to make things clearer: impl dyn Foo {, fn f1(foo: &dyn Foo), etc.

1 Like

This makes the method available only on Foo trait objects, and that requires you to coerce to one in f2.

Still don’t understand why rust doesn’t coerse it automatically. Seems to be safe and obvious thing to me.

Make utility_shortcut a free function that takes a &Foo trait object.

This is somewhat not ergonomic.

Create a separate trait, let’s call it FooExt, that contains the util method. Then impl it for Foo and for F: Foo

Then this FooExt trait could be added to my prelude module and will be available. This is probably what I should do. Thank you!