# Macro with variable argument list combined with closure

**URL:** <https://discourse.julialang.org/t/macro-with-variable-argument-list-combined-with-closure/117623>\
**Category:** General Usage\
**Tags:** macros, metaprogramming, closure\
**Created:** [July 30, 2024, 7:38am UTC](https://discourse.julialang.org/t/macro-with-variable-argument-list-combined-with-closure/117623 "2024-07-30T07:38:35Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![nietzsche](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nietzsche/32/214748_2.png) [@nietzsche](https://discourse.julialang.org/u/nietzsche)\
**Post date:** [July 30, 2024, 7:38am UTC](https://discourse.julialang.org/t/macro-with-variable-argument-list-combined-with-closure/117623/1 "2024-07-30T07:38:35Z")

</div>

Hi,  
i have a question about variable arguments in macros together with the scope of them.

Function count\_test() should be a closure over the variable _count_ and the lambda should be generated with a macro.

It should be possible to manipulate the count variable by sending a message (:inc or :dec), **but the variable count will NOT change.**

I did a macroexpand and the scope of _count_ is NOT the Main, so the ESC was succesful. But anyway the count varibable do NOT change.

The example is from the book LetOverLambda Chapter 5.7.

Thanks

```julia
macro counter_macro(body...)
    return quote
        println("macro")
        (msg) ->
            begin
                if $(body[1])[1] == msg 
                    println("test inc")
                    $(esc(body[1]))[2] = $(esc(body[1]))[2] + 1  
                end
                if $(body[2])[1] == msg 
                    println("test dec")
                    $(esc(body[2]))[2] = $(esc(body[2]))[2] - 1 
                end
            $(esc(body[2]))[2]
        end
    end
end
function count_test()
    count = 0
    return (@counter_macro [:inc count] [:dec count])
end

c2 = count_test()
c2(:inc)
c2(:inc)
c2(:inc)
c2(:dec)

```

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [July 30, 2024, 11:05am UTC](https://discourse.julialang.org/t/macro-with-variable-argument-list-combined-with-closure/117623/2 "2024-07-30T11:05:25Z")

</div>

In your `if` blocks, when you write

```julia
$(esc(body[1]))[2] = $(esc(body[1]))[2] + 1

```

this is macroexpanded to

```julia
([:inc count])[2] = ([:inc, count])[2] + 1

```

which is a `setindex!` expression on an array, not a lexical rebinding.

I would instead write this as

```julia
macro counter_macro(body...)
    quote
        println("macro")
        (msg) ->
            begin
                if $(body[1].args[1]) == msg 
                    println("test inc")
                    $(esc(body[1].args[2])) = $(esc(body[1].args[2])) + 1  
                end
                if $(body[2].args[1]) == msg 
                    println("test dec")
                    $(esc(body[2].args[2])) = $(esc(body[1].args[2])) - 1 
                end
            $(esc(body[2].args[2]))
        end
    end
end

```

(Well, actually I also wouldn’t use a variable argument list since you clearly only actually support two arguments, and have a pre-defined expectation for what sort of structure you want those arguments to have, but I guess that’s another topic)

With the above changes, I get

```julia-repl
julia> c = let count = 0
           @counter_macro [:inc count] [:dec count]
       end
macro
#10 (generic function with 1 method)

julia> c(:inc)
test inc
1

julia> c(:inc)
test inc
2

julia> c(:dec)
test dec
1

julia> c(:dec)
test dec
0

```

---

<div class="post-metadata">

**Author:** ![nietzsche](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nietzsche/32/214748_2.png) [@nietzsche](https://discourse.julialang.org/u/nietzsche)\
**Post date:** [July 30, 2024, 11:19am UTC](https://discourse.julialang.org/t/macro-with-variable-argument-list-combined-with-closure/117623/3 "2024-07-30T11:19:06Z")

</div>

Works perfekt. Thanks.  
In the next step I will abstract away the if clauses, thats why I use a variable list.
