Invoke for functor methods

A minimal example demonstrating the use of invoke() might look something like the following.

julia> abstract type A end
       struct B <: A end
       f(a::A) = "hello world from $a"
       f(b::B) = invoke(f, Tuple{A}, b)
       f(B())
"hello world from B()"

Now imagine that rather than having a function f(), I want to use values of type A and B as functors instead. In this case, is there an analogous way to dispatch to the A functor?

(a::A)() = "hello world from $a"
(b::B)() = invoke( #= ??? =# , Tuple{A}, b)

This question is driven mainly by curiosity. In my actual code, I currently just dispatch to the above helper function f().

(a::A)() = f(a)

AFAICT this works fine, I’m just curious whether there would be a way to get rid of the additional helper function.

2 Likes

Not directly. The fundamental issue here is that method signatures vary over the types of the callable and the positional arguments, but invoke only allows us to specify the positional arguments. In this case, invoke(b,...) cannot specify a b() call to use the (a::A)() method. Shifting the implementation to arguments of a const-named helper function and forwarding all functor calls to it is as good as it gets for invoke.

In the grander scheme, there are many functions that seem designed for the vast majority of named functions yet could reasonably be extended to other callables. This is a bit of a double whammy because invoke is also rarely used outside of reflection; deleting the b::B method with invoke from your minimal example would let B()() “invoke” the (a::A)() method, for instance.

1 Like