Does Julia support the reflection just like java?
What I need is something like this:
str = ARGS[1] # str is a string
# invoke the function str()
Does Julia support the reflection just like java?
What I need is something like this:
str = ARGS[1] # str is a string
# invoke the function str()
The Good Way
The recommended way to do this is to convert the function name to a symbol and then look up that symbol in the appropriate namespace:
You can change
Main
here to any module to only look at functions in that module. This lets you constrain the set of functions available to only those available in that module. You can use a "bare module" to create a namespace that has only the functions you populate it with, without importing all name fromBase
by default.The Bad Way
A different approach that is not recommended but which many people seem to reach for first is to construct a string for code that calls the function and then parse that string and evaluate it. For example:
While this is temptingly simple, it's not recommended since it is slow, brittle and dangerous. Parsing and evaling code is inherently much more complicated and thus slower than doing a name lookup in a module – name lookup is essentially just a hash table lookup. In Julia, where code is just-in-time compiled rather than interpreted, eval is much slower and more expensive since it doesn't just involve parsing, but also generating LLVM code, running optimization passes, emitting machine code, and then finally calling a function. Parsing and evaling a string is also brittle since all intended meaning is discarded when code is turned into text. Suppose, for example, someone accidentally provides an empty function name – then the fact that this code is intended to call a function is completely lost by accidental similarity of syntaxes:
Oops. That's not what we wanted at all. In this case the behavior is fairly harmless but it could easily be much worse:
If the user's input is untrusted, this is a massive security hole. Even if you trust the user, it is still possible for them to accidentally provide input that will do something unexpected and bad. The name lookup approach avoids these issues:
The intent of looking up a name and then calling it as a function is explicit, instead of implicit in the generated string syntax, so at worst one gets an error about a strange name being undefined.
Performance
If you're going to call a dynamically specified function in an inner loop or as part of some recursive computation, you will want to avoid doing a
getfield
lookup every time you call the function. In this case all you need to do is make aconst
binding to the dynamically specified function before defining the iterative/recursive procedure that calls it. For example:The binding
f
must be constant for optimal performance, since otherwise the compiler can't know that you won't changef
to point at another function at any time (or even something that's not a function), so it has to emit code that looksf
up dynamically on every loop iteration – effectively the same thing as if you manually callgetfield
in the loop. Here, sincef
isconst
, the compiler knowsf
can't change so it can emit fast code that just calls the right function directly. But the compiler can sometimes do even better than that – in this case it actually inlines the implementation of thedeg2rad
function, which is just a multiplication bypi/180
:If you need to do this with many different dynamically specified functions and you're using Julia 0.5 (nightly), then you can even pass the function to be called in as an argument:
This generates the same fast code as single-argument
fast
above, but will generate a new version for every different functionf
that you call it with.