Im trying to evaluate a string as a function within a function. I have made good progress:
function Evaluate(some_function::String ; variables = [:x])
g = genfun(Meta.parse(some_function), variables)
This allows me to write Evaluate(“some function”)(x)
which is good, but if I want to evaluate this inside another function, for example:
function foo(some_function::String ; variables = [:x])
x = 1
I get an Error
MethodError: no method matching (::getfield(SyntaxTree, Symbol("##137#138")))(::Float64)
The applicable method may be too new: running in world age 26255, while current world is 26256.
Closest candidates are:
#137(::Any) at /Users/joe/.julia/packages/SyntaxTree/Adq4Y/src/SyntaxTree.jl:144 (method too new to be called from this world context.)
 h(::Float64) at ./In:1
 WaveFunctionNumerov(::String, ::Float64, ::Int64, ::Float64, ::Float64, ::Float64) at ./In:24
 top-level scope at In:52
Why is this a problem in the first place and how can I get around it?
the evaluation really needs to be within a function
First thing first: why?
I ask because I see people try to do this a lot, and it has never been the right answer.
That being said, it looks like
genlatest which should work, since it calls
Base.invokelatest, getting around the world age issue. Again, this is probably the wrong approach to the problem, with plenty of negative performance and runtime consequences, so I urge you to reconsider.
Hi, i am the creator of
SyntaxTree and I recommend using Julia expressions for metaptogramming if possible instead of parsing strings, as @tomerarnon mentioned it is not so good to use strings for this in general.
Indeed, the purpose of
genlatest is to get around the world age issues.
The problem is that
genfun most likely uses
eval always runs at runtime. Therefore, when the compiler looks at
eval has not been run yet, so it doesn’t have any way of knowing what to do with the call
Evaluate(some_function)(x). This is what it means for
g to only be defined in a newer world age. You can use
Base.invokelatest, to work around this, but that has quite a big performance penalty. An alternative might be to use RuntimeGeneratedFunctions.jl, which can build functions from expressions at runtime without the use of
eval, but is a bit hacky.
The idea is that when running the julia script, the script will ask for an input, (in the form of a String or Expr) and then run the program from there making the program more dynamic and diverse.
I will try the genlatest, although I’d be more than happy to hear a more effective solution if you have one?
Why would this make a difference? Surely parsing a String into an Expr is effectively the same thing as just taking an Expr as input?
True, in this case using a string or an expr would be the same (and suffer from the same limitations).
If you intend to create a function from a user inputted string, consider separating the
Evaluate function into two separate operations in your script. First create the
genfun function (which will no longer need to be
genlatest, as a result of this split) and then pass the created function on to another function to do the work. This will ensure type stability and will therefore be more performant.
g = Evaluate(user_input) # type unstable, but who cares?
foo(g) # foo is specialized to typeof(g) now!