Inside a function, I would like to evaluate a module’s function based on two inputs: 1) the module itself and 2) the function’s name as a string. Here is the code:
println("This is A.foo")
function bar(m::Module, s::String)
# evaluate "m.s"
I have several questions:
How can I evaluate "m.s" inside the bar function to produce the expected output?
julia> bar(A, "foo")
This is A.foo
Do you have suggestions about better practices to achieve what I would like to do? I explain a bit more: the bar function will belong to a package that will handle some user-defined modules (in our example: A would be defined by a user). At end, a user would have to code module A and to write the functions inside (such as foo) in a config file. This config file design choice makes it easier to pass the function names as strings. While I am confident about the fact that I shall pass the function’s name as input, I do not know if it is a good thing to pass a whole module as input.
In answer to your broader question about whether this is a good approach in general, I would
ask why the package that bar belongs to needs to interact with modules at all. If bar
can be passed a module object, why can’t it just directly be passed foo?
This is related to some design choice: from the user’s point of view, we have to provide 1) the A module containing some functions such as foo and 2) a config file listing the functions inside A that will be used during the global execution. To make it clearer, say we have foo1 and foo2 inside A. The user could then be willing to use bar with maybe only foo1 during the global execution. Later, during another run, the user would be using foo1andfoo2. Truth is that I will be passing the list of used functions as strings and all this could be achieved simply with the config file.
I would avoid relying on eval for this, instead using getfield or getproperty on the module object:
julia> module A
foo() = "Hello"
julia> function bar(mod, name)
fun = getfield(mod, name)
bar (generic function with 1 method)
# Passing the name directly as a Symbol
julia> bar(A, :foo)
# Or converting the String to a Symbol
julia> bar(A, Symbol("foo"))
Thanks! What is the advantage of getfield over eval?
I noticed allocation and computational improvements:
println("This is A.foo")
function bar1(m::Module, s::String)
function bar2(m::Module, s::String)
s = "foo"
@btime bar1(A, s) # 28.833 μs (20 allocations: 608 bytes)
@btime bar2(A, s) # 8.229 μs (6 allocations: 144 bytes)
And the reason I do not directly pass an array containing the functions A.foo1 and A.foo2 themselves is that I want the user to specify the function names inside a configuration file. The user-defined module A is something fixed but depending on the case, one would want to specify different functions of A in the configuration file.