Reputation: 19132
I am trying to define a macro for a function template, i.e. a template where you can easily drop in relevant code but don't want to expose all of the nitty-gritty implementation details to the user. For example, I would like something like this that drops an expression into a more complex function:
macro make_complex_function(ex)
quote
function (alg,f,t,u,k)
# Add some stuff on top
condition1 = false
condition2 = false
#...
#Put in the user's code
$(esc(ex))
# Put a footer
return some,stuff,here,long,annoying,list
end
end
end
so a user could easily insert small bits of logic (with a simplified API / documentation):
easy_func = @make_complex_function begin
if u > 1
print("oh no! It happened!")
end
end
while the full power is still available for more advanced users. However, if you run that code you'll get access to undefined reference errors. I think it's because I am not escaping the expression properly, and should somehow be escaping the entire function, but am not sure how.
Upvotes: 2
Views: 83
Reputation: 2862
short answer: do NOT use esc
or put it on the whole quote
block.
julia> macro m(e)
quote
function f(x)
return $(e)
end
end
end
@m (macro with 1 method)
julia> f = @m x+1
#1#f (generic function with 1 method)
julia> f(2)
3
julia> macro m(e)
esc(quote
function f(x)
return $(e)
end
end)
end
@m (macro with 1 method)
julia> f = @m x+1
f (generic function with 1 method)
julia> f(2)
3
long answer:
julia will prefix any names defined inside a macro, making them unreachable anywhere else. esc
will cancel these prefixes so that the names in the final expression are exact what you write. So remember only use esc
if you need to access these variables outside the macro, which is not the case your example.
macroexpand
to help building macroesfor example, if you put the esc
at the wrong place like following:
macro m(e)
quote
function f(x)
return $(esc(e))
end
end
end
you will got such a expression:
julia> macroexpand( :( @m x+1 ) )
quote # REPL[9], line 3:
function #1#f(#2#x) # REPL[9], line 4:
return x + 1
end
end
You can find that the f
and it's argument are prefixed by a special thing(as they are not escaped), while the body is simply x
, which is not defined anywhere.
Generally, it's better to use higher-order functions to implement "function templates", as they are easier to read and can take advantage of modern static analysis tools - though it seems Julia did't have one yet :). Write function signatures and pass them seems annoying, but they worth it.
Upvotes: 5