Hi,
this is my first post. I have a question about macros and closures. The example is from the Book “LetOverLambda” Chapter 5.7. The author called it DLambda.
The following source is a easy counter closure
function counter()
count = 0
return (msg) -> if msg == :inc
count = count +1
elseif msg == :dec
count = count -1
end
end
if I do. The result is 2. Everything fine
c1 = counter()
c1(:inc)
c1(:inc)
Now I want abstract it away with a macro
macro counter_macro(msg, p1)
return quote
if $msg == :inc
() -> println($p1)
end
end
end
function counter1()
counter123 = 0
return (@counter_macro :inc counter123)
end
But then there is a error, because counter123 is NOT defined. The problem is, that he want to use Main.counter123 as variable.
How can I solve this, suchthat counter1 is a closure und has the same result than counter?
@macroexpand @counter_macro :inc counter123
Hi there!
What is your question about the code?
Also note that this example has nothing to do with metaprogramming/macros. You define a closure, which is essentially just a function that carries along some extra state (in this case the variable count
). You could write an equivalent code (and in fact this is what Julia does internally):
# struct to hold the state
struct Counter
count::Int
end
# this is the function you wrote
function counter()
return Counter(0) # just create an instance of Counter starting at 0
end
# this makes the instance callable
function (counter::Counter)(msg)
if msg == :inc
counter.count += 1
elseif msg == :dec
counter.count -= 1
end
end
1 Like
sorry…i needed some time to write the post. now it is ready
Don’t worry
The issue you are facing here is because Julia has automatic macro hygiene. This essentially means that every symbol that a macro returns is gensym
ed. So when you interpolate the variable name here () -> println($p1)
then it will be a different symbol after macro expansion, which explains the error. You need to esc
ape the symbol:
macro counter_macro(msg, p1)
return quote
if $msg == :inc
() -> println($(esc(p1)))
end
end
end
With this your function counter1()
returns a closure that prints the value of the captured variable counter123
when called.
Edit: You would face the same problem with msg
if tried to use a variable/expression at the call site. It only works for a constant value.
1 Like
Thanks a lot…it was so easy. i thought about the ESC command, but i didnt get it