Dynamically invoke all the methods of a function

I want to write a function A.x() which in its body automatically invokes all the available methods of A.x(). However, I can’t find the reflection mechanism that allows me to do this. I was hoping methods will do it, but it doesn’t return functions, ex:

julia> [r() for r in methods(rand)]
ERROR: MethodError: objects of type Method are not callable

Also, I would like to get the Module in which the method was defined.

Is it possible? Thanks

Every method may take different arguments though… Does your use case only need to handle calling it without any arguments?

The Method object contains a module field e.g.

julia> struct Foo end

julia> using Random

julia> Random.rand(::Foo) = 1

julia> unique([m.module for m in methods(rand)])
2-element Array{Module,1}:
 Random
 Main

Thank you - the methods are part of an interface so I’m thinking of specialising them on something like Val{Symbol(@__MODULE__)} so then I can invoke them using the module’s name.

The module field is great - but how can I get the function from the method object and how do I invoke it?

GitHub - cstjean/ConferenceCall.jl ?

3 Likes

I thought you already have a reference to the function to begin with? :thinking: Invoking the function is just simply calling it with the right arguments.

I guess it can become tricky to make it dispatch to the exact method. For example, if you have two methods - one taking Int and another taking Number, then you have to figured out how to call the second method with a non-Int Number. Maybe your use case is simpler than what I am imagining…

I was looking to get a reference to the function within the methods iteration. But you’re right, given that I already have the function’s name and I get the module within the iteration, I can just invoke it “by hand”.

Yes, it’s a simpler situation in terms of arguments as these are for an interface, so I know what argument they will take by convention.

However, this is becoming complicated enough and dubious enough to look like a code smell. So I refactored my code so that each module, instead of extending the main function, pushes its function into an array in the main package. The code now just iterates over the functions pushed in the array which is a pretty common Julian design pattern.

Thanks for your help!

This is beautiful, thank you! It’s exactly how I defined the functions, using a Val based on the module’s name as the convention for the interface. But this is much cleaner and less error prone, with the automatically generated signature.

1 Like

I considered that solution for my use cases too, but push!(OtherPackage.array, my_function) at the top-level doesn’t work with precompilation. It has to be in the __init__, which is inconvenient.

1 Like

Yes, I figured that out myself. Functions were not being added to the array but no warning or anything… So I just tried in __init__ and was happy to see that it works. I’m OK with this as it’s for developers wanting to write plugins to interface with the package.