# Assigning inside a macro, and proper way to create this expr

I (as a beginner to macros) was looking to write a macro `@deal` such that I could write:

``````@deal R a b
``````

(where `length(a)+length(b)==length(R)`), and have it distribute the values in R into a and b - for eg. if `length(R)==10`, `length(a)==4`, `length(b)==6`, then R[1:4] would go into a, and R[5:10] into b.

Similarly `@deal R x y z`, with x, y, z having lengths 2, 5, and 3 respectively, should effectively mean `x[:] = R[1:2]`, `y[:] = R[3:7]`, `z[:] = R[8:10]`.

I barely understand macros though, and after a lot of bumbling around came up with this:

``````macro deal(V, x...)
assigns = quote starter = 1 end
for i in 1:length(x)
push!(assigns.args, (quote
esc(\$(x[i])) = esc(\$V)[starter:starter + length(esc(\$(x[i])))]
starter += length(\$(x[i]))
end).args)
end
assigns
end
``````

I’m sure it’s terrible in all sorts of ways, but it doesn’t even work - the assignment to `esc(\$(x[i])` ends up being seen as a function definition `esc(a)` and so doesn’t change the values of a or b.

How does one assign to a caller-scope variable inside a macro correctly?

And what’s the not-so-terrible way to write this macro? Hints towards how I can add things like type-checking and length-checking are also welcome.

The `esc` goes inside the interpolation, say `esc(\$V)` should be `\$(esc(V))`, as `esc` acts on the symbols and is not passed onward to the code which the macro generates.

Thank you! `esc` had been one large part of what confused me about macros (it just seemed too magical and handwavy before), but your explanation prompted me to try it out on the REPL by itself, and I believe I have a better understanding of it now.

Here’s my current code for the macro:

``````
macro deal(V, x...)
assigns = quote
starter = 1
C = \$(esc(V))
end

for i in 1:length(x)
q = quote
a = \$(esc(x[i]))
a[1:end] = C[starter : starter + length(a) - 1]
starter += length(a)
nothing
end
append!(assigns.args, q.args[2:end])
end

assigns
end
``````
1 Like

It is unclear why you need a macro for this. Eg

``````function deal!(src, dest...)
i = 0
for d in dest
n = length(d)
d .= src[(i+1):(i+n)]
i += n
end
# length checking and generalized indexing
# left as an exercise for the reader 😎
end

R = 1:10
a = zeros(4)
b = zeros(6)
deal!(R, a, b)
``````
4 Likes

True enough. I was thinking that a macro would let me add code to handle more complex input in the future, things like:

``````julia> c = ones(7);

julia> @deal R a[2:4] c
``````

(right now, neither the macro nor the function change the contents of `a` in this case.)

But such uses are rare enough that I can afford to simply write it as `deal!(R, @view(a[2:4]), c)` rather than try to make too DWIMmy a macro.

The other reason was to try and understand macros better through writing this - and that part worked out reasonably well. 