Call trait method implemented on `fn` without casting as

Given the following trait and implementations:

trait Exec {
    fn exec(self);
}

impl Exec for fn() {
    fn exec(self) { self(); }
}

impl Exec for fn(i32) {
    fn exec(self) { self(10); }
}

You cannot call Exec::exec on an implemented function without casting it as fn(...).

fn foo() {}

Exec::exec(foo); // Fails
Exec::exec(foo as fn()); // Works

I don't see any reason why this cast should be necessary for Rust to figure out how to call the trait method.

This causes issues in my case since I'm building a macro, and receive function names, but cannot call exec since I don't know the function's signature (and I shouldn't have to).

For example:

fn foo() {} // implements Exec
fn bar(a i32) {} // implements Exec
exec_functions![foo, bar];

My exec_functions! macro doesn't know the signature of foo and bar to be able to call Exec::exec on, since a cast is required.

Any idea why this is the case, and if there might in fact be a way to avoid the fn cast? One work-around would be to implement Exec for F: Fn(A), A: Args, and implement Args for tuples with a varying number of items. Though I don't see why I should need to use a workaround for this.

Thank you

1 Like

You probably can do as _, so that Rust will infer the specific type for you. Or you can do impl<F: Fn(i32)> Exec for F, to cover not only function pointers, but also function items and closures.

as _ sadly doesn't work.

impl<F: Fn(i32)> Exec for F would only allow Exec to be implemented for functions which take 1 parameter, where my goal is to implement it for functions taking 0 to many parameters.

The problem is that every function has its own, distinct, function item type whereas your trait is only implemented on function pointers (and cannot be implemented on function item types, because there's no syntax for doing so—and it wouldn't be especially useful even if there was one, as such an implementation would only be for that single function).

Explicitly casting the function item typed reference into a function pointer (as you are currently already doing) is probably your best option here. Alternatively you could explicitly specify the Self type of the trait reference, in which case the function reference should be coerced to a function pointer automatically:

<fn() as Exec>::exec(foo);

But that's probably no more useful to you than the explicit cast.

2 Likes
trait Exec<_Arg = ()> {
    fn exec(self);
}

impl<F : FnOnce()> Exec for F {
    fn exec(self) { self() }
}
impl<F : FnOnce(i32)> Exec<i32> for F {
    fn exec(self) { self(10) }
}

fn foo() {}

foo.exec(); // works!
(|x| { dbg!(x); }).exec() // works!

That being said, I'd advise against giving self-based methods to fns and closures in general. This is what ::syn does with the .parse… methods and it's one of the most counter-intuitive and undiscoverable pieces of API of the crate;

  • e.g., how do you try to parse a TokenStream into a Field?

    use ::proc_macro2::TokenStream;
    use ::syn::{Field, Result};
    
    /// Parse a named field `a: Ty`.
    fn challenge (input: TokenStream)
      -> Result<Field>
    
    use ::syn::parse::Parser;
    Field::parse_named.parse2(input)
    

    which is why I personally don't even use that method syntax available, and instead use:

    ::syn::parse::Parser::parse2(/* with */ Field::parse_named, input)
    

So I'd recommend to:

- fn exec (self: Self) {
+ fn exec (this: Self) {

to ensure the calls necessarily happen as:

Exec::exec(foo);
Exec::exec(|x| { … });
4 Likes