I have two long macros that are almost equal, apart from a few lines:
macro m1(#= args of m1... =#)
# set some variables in m1 and m2 before returning the expression...
# define some other variables only in m1...
quote
# first part of the body in common to m1 and m2...
# this is only in m1...
# second part in common to m1 and m2...
end
end
macro m2(#= args of m2... =#)
# set some variables in m1 and m2 before returning the expression...
quote
# first part of the body in common to m1 and m2...
# second part in common to m1 and m2...
end
end
What’s the best strategy to manage this code and reduce code duplication? I guess I should define functions working on expressions, but I don’t really know how to do that in practice, also because given how @m1 is defined I’d need to concatenate multiple Expr and I have no idea how this works.
Right, this makes sense and works, thank you so much!
I’m almost done. If I’d like to move also the part before the returned expression to a function, I’d have to do that? Should the function return an expression that has to be @evaled in the macro?
No, you should never need to call @eval or eval() within a macro. Your macro should just call the function returning an expression, no further action needed.
For example:
julia> function make_expr()
return :(2 + 2)
end
make_expr (generic function with 1 method)
julia> macro foo()
return make_expr()
end
@foo (macro with 1 method)
julia> @macroexpand @foo()
:(2 + 2)
julia> @foo()
4
I asked about what is before the returned expression, the “preamble” (is there a specific term to identify this part of the macro?), where I set some variables that will be used within the returned expression.
In this part you could use “standard” (i.e. not macro-specific) code factoring techniques : regular functions taking some arguments and returning the set of values which you want to use in the remaining part of your macro.
julia> @macroexpand @m1 x
quote
#= REPL[5]:5 =#
begin
#= REPL[3]:2 =#
(Main.println)(1, 2, x)
end
#= REPL[5]:6 =#
begin
#= REPL[4]:2 =#
(Main.sum)((1, 2, 3, x))
end
end
julia> let x = 4
@m1 x
end
124
10