A question about defining a function inside another using metaprogramming

first-steps
#1

Consider the following code for defining a function from a symbolic expression, using the metaprogramming facilities of Julia:

expression_G = :(x^3)
G = eval(:(x->$expression_G))
println(G(3)) 

it works as expected and prints the value 27. However, if you do exactly the same inside a function.

function f()
 expression_G = :(x^3)
 G = eval(:(x->$expression_G))
 println(G(3)) 
end 

f()

you get an error message like this one:

include("example2.jl")
ERROR: LoadError: MethodError: no method matching (::getfield(Main, Symbol("##5#6")))(::Int64)
The applicable method may be too new: running in world age 25570, while current world is 25571.
Closest candidates are:
  #5(::Any) at /home/pablo/programitas/test/example2.jl:3 (method too new to be called from this world context.)
Stacktrace:
 [1] f() at /home/pablo/programitas/test/example2.jl:4
 [2] top-level scope at none:0
 [3] include at ./boot.jl:326 [inlined]
 [4] include_relative(::Module, ::String) at ./loading.jl:1038
 [5] include(::Module, ::String) at ./sysimg.jl:29
 [6] include(::String) at ./client.jl:403
 [7] top-level scope at none:0
in expression starting at /home/pablo/programitas/test/example2.jl:7

What is happening and can I do something about it? (I guess that
this is related to when the code is actually gets compiled.)

0 Likes

#2

See https://docs.julialang.org/en/v1/manual/methods/#Redefining-Methods-1.

The function won’t be visible until execution returns to the top level, which is when the world-age-related updates happen. You could use Base.invokelatest(G, 3) if you want to call G inside f, but there’s a bit of a performance penalty for doing that.

Note that typically, there’s a better way than evaling expressions in a function to solve the same problem.

3 Likes