Hello,
I’m exploring an idea which may look funny. Please tell me if you thinks it’s impossible or useless.
My goal
I’d like to generate automatically (with metaprogramming I guess) functions which body and signature comes from an existing function “template” and then appending a return statement (return myvar where myvar can be decided in the code). Here is an illustration.
The function “template” model is a model of physical system which computes many variables (only 3 (c,d,e) in this dummy example).
function model(a,b)
c = 2*a
d = c+b
e = d^2
end
To provide more context, this model will be used in several optimization variants, like:
- minimize
d - minimize
ds.t.e≤ 2 - minimize
e+d - …
These variants should be user selectable.
To support the variants without duplicating the code of model, I’d like an easy way for the user my optimization tool to select the relevant output(s) of model. So I’ve imagined I could have macro which could be invoked as:
@set_return model_retc model :c
And this would generate the function:
function model_retc(a,b) # function name set in macro invokation
# signature and body copy-pasted from `model`
c = 2*a
d = c+b
e = d^2
return c # returned variable(s) set in macro invokation
end
It’s not clear to me how to do this. I’ve searched two approaches:
- Get the AST of the template function, but I kind of understood that AST is defined for specific methods rather than the generic function (SO: Access the AST for generic functions in Julia)
- Get the source code of the template function, but I didn’t go all the way. Only, I found on SO How to print in REPL the code of functions in Julia? which seems to indicate that it’s not working for REPL-defined functions.
- Also, the
@lessmacro is about opening the source in a pager, but I just want to get the source in a variable.
Also, I got from Write Julia macro that returns a function that to create a function in a macro, it is necessary to have the the content known at compile time, not at execution time. I think in my case all information is available in the source code.
Alternative without metaprogramming: is it good enough?
Since I don’t know how to achieve my goal with metaprogramming, I’m using an approach based on 1) returning all variables of potential interest and 2) select those in a wrapper.
The function which return “all” is:
function model_retall(a,b)
c = 2*a
d = c+b
e = d^2
return Dict(:c => c, :d => d, :e => e)
end
Then I can create (manually or with a short function factory):
function model_retc(a,b)
model_retall(a,b)[:c]
end
My questions on this metaprogramming-less approach are:
- Are there better alternatives than returning a
Dictof variables?- This approach is actually insired by an existing Python tool which enforces a convention that all model functions should
return locals(), i.e. all local variables?
- This approach is actually insired by an existing Python tool which enforces a convention that all model functions should
- Is there some performance issue related to returning many outputs kike in
model_retalland then dropping most of them (e.g.dandeends up being unnecessary to computec)- in particular, in my optimization approach, I want to compute the gradient of
model_retcwith some AD package (ForwardDiff, Zygote, other…?)
- in particular, in my optimization approach, I want to compute the gradient of