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[2])
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
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)