f(x) = (; a=2x, b=x*x)
macro ma(x)
quote
f($x)
end
end
macro mb(x)
quote
nt = f($x)
(; nt.a, nt.b)
end
end
macro mc(x)
quote
(; a,b) = f($x)
end
end
while ma and mb behaves kindly IMO
using Test
@test (@ma 1) == (; a=2, b=1) # ok
@test (@mb 1) == (; a=2, b=1) # ok
@test (@mc 1) == (; a=2, b=1) # bug
mc errors immediately (at the lowerer ?)
There may be some unification issues in regard to non-escaped / re-gensymd a,b
but we should be able to destructure first IMO .
Comment advices welcome
macro md(x)
nt = :((; a, b))
quote
$(esc(nt)) = f($x)
end
end
julia> @macroexpand @mc 1
quote
#= Untitled-1:67 =#
(; a = Main.a, b = Main.b) = Main.f(1)
end
julia> @macroexpand @md 1
quote
#= Untitled-1:74 =#
(; a, b) = Main.f(1)
end
Yes this seems kind of buggy/ill-defined to me. If the symbols a and b are not escaped, I would expect the output to be something like (; var"#1#a", var"#2#b") = ... because the new variables should have gensymmed names. Instead these a = Main.a assignments are created, which of course cannot work.
But because gensymmed names would not access the correct variables from the destructured object, this also cannot work.
Interesting case because property access and variable creation are intertwined in this syntax, and while property symbols are not subject to macro hygiene, variable creation is, so that is kind of incompatible.
IMO the issues come from the fact the lowerer does too few passes eg. 5 passes only, first one is ~ 2.5KLOC of femtolisp. It’s a monolithic (and archaic) code nowadays.
There should be many more passes (compare to go, rust, fsharp, no surprise, they all go this way).
This will be possible to stage those kinds of issues correctly
JuliaSyntax will be important at some point, (and countdown has begun a couple of years ago)