I’m trying to implement the following scenario: based on some configuration, I want to build an expression which essentially defines a function:
function build(config::String)
:(function p() println($config) end)
# or :(() -> println($config))
end
ex = build("test")
And then pass the compiled function to another method:
function test(f::Function)
f()
end
test(eval(ex))
# prints "test"
The eval however has a side effect of introducing function p() (or if it has no name, then anonymous function) in the current global scope. Does anybody know how to achieve the same goal while not introducing additional definitions to the global scope, like
const f = compile(ex)
f()
# prints "test"
methods(p)
# p not defined
function build(config::String)
function p() println(config) end
end
const f = build("test")
f()
never introduces p() to global scope (or module scope to be precise). However I need more flexibility and construct the body of this function dynamically. Are you aware of any other methods which might be helpful here?
Yes, this is so far the only solution I know, with the only drawback that with each call it adds a new anonymous function to a global scope (current module). When working with a normal nested function, nothing extra goes outside, so I wondered whether the same is possible with eval.
Actually it is interesting whether this is a viable workaround, as suggested by @sdanisch:
function build(config)
ex = make_body(config)
temp = Module()
eval(temp, :(() -> $ex))
end
but I suspect that this anonymous module will be hanging around till the end.
Thank you for suggestion, but generated functions seem to only provide information about the type of arguments, while I build an expression at runtime based on some config object.
Because function build is supposed to build a function body (or entire function), based on a passed config. I just provided a minimalistic example. It could be as well something like this:
function build(config::Config)
body = Expr(:block)
fexpr = Expr(:function,:(make(template::Template)), body)
push!(body.args, :(local obj::SomeObj))
current_block = body
for i in 1:length(config.types)
mexpr = config.construct_expr[i]
code = sd.codes[i]
elseexpr = Expr(:block)
ifexpr = Expr(:if, :(template.code == $code), :(obj = $mexpr), elseexpr)
push!(current_block.args, ifexpr)
current_block = elseexpr
end
push!(body.args, :(return obj))
fexpr
end