Yaay another funny one ^ ^" Can someone explain what's happening to variable a in there? ^ ^"
macro m()
a = __source__
println("during expansion: ", a)
xp = quote
println("during execution: ", $a)
end
println("in the generated xp: ", xp.args[2].args[3])
xp
end
@m # (line 10)
during expansion: #= ./test.jl:10 =#
in the generated xp: #= ./test.jl:10 =# still there: so it's not "killed" by the `$`-injection
during execution: nothing .. !? where did it go?
(tried a = deepcopy(__source__) with no success)
(ended up just collecting the desired (; file, line) = __source__ instead with no problem, just curious why this happens)
I think it's that lowering strips line number nodes out of code.
Oh, by replacing them with nothing :)
That makes sense. I just need to protect it from stripping somehow then.
Yup: a = Ref(__source__) does the trick :)
Thanks <3
julia> quote
x + 1
x + 2
end
quote
#= REPL[15]:2 =#
x + 1
#= REPL[15]:3 =#
x + 2
end
julia> Meta.lower(Main, ans)
:($(Expr(:thunk, CodeInfo(
@ REPL[15]:2 within `unknown scope`
1 ─ %1 = Main.:+
│ %2 = Main.x
│ dynamic (%1)(%2, 1)
│ @ REPL[15]:3 within `unknown scope`
│ %4 = Main.:+
│ %5 = Main.x
│ %6 = dynamic (%4)(%5, 2)
└── return %6
))))
iago-lito said:
Yup:
a = Ref(__source__)does the trick :slight_smile:
You can use QuoteNode for this too
Or just (__source__,).. really anything.
julia> macro m()
a = __source__
println("during expansion: ", a)
xp = quote
println("during execution: ", $(QuoteNode(a)))
end
println("in the generated xp: ", xp.args[2].args[3])
xp
end
@m (macro with 1 method)
julia> @m
during expansion: #= REPL[18]:1 =#
in the generated xp: $(QuoteNode(:(#= REPL[18]:1 =#)))
during execution: #= REPL[18]:1 =#
QuoteNode IMO is the preferred mechanism, because it's like how you'd put a literal symbol in generated code
Ok. What's the difference with Meta.quot?
julia> macro foo()
x = :blah
:(show($x))
end
@foo (macro with 1 method)
julia> @foo
ERROR: UndefVarError: `blah` not defined in `Main`
Suggestion: check for spelling errors or missing imports.
Stacktrace:
[1] top-level scope
@ REPL[20]:1
julia> macro foo()
x = QuoteNode(:blah)
:(show($x))
end
@foo (macro with 1 method)
julia> @foo
:blah
Oh I see: https://docs.julialang.org/en/v1/manual/metaprogramming/#man-quote-node.
I never really got the difference tbh. Never needed Meta.quot
The difference is that Meta.quot still does interpolation, while QuoteNode doesn't even. As per the example in the docs:
julia> eval(Meta.quot(Expr(:$, :(1+2))))
3
julia> eval(QuoteNode(Expr(:$, :(1+2))))
:($(Expr(:$, :(1 + 2))))
It is even more litteral :P
Honestly I am finding that julia macro system is by far the most ergonomic and sophisticated I know.
It's quirky and complex for sure, but I think this is inherent to codegen. I think that is just the irreducible complexity part of metaprogramming. I love it <3
(or maybe I should move that to #appreciation? ;)
yeah it's quite good
the new macro system being developed seems quite neat too
This topic was moved here from #general > __source__ decaying to 'nothing' after macro expansion? by Mason Protter.
This topic was moved here from #helpdesk > __source__ decaying to 'nothing' after macro expansion? by Mason Protter.
Recently updated at https://github.com/JuliaLang/julia/pull/62587 if either of you want to try examples (feel free to leave comments if anything is unclear). Many things were changed or figured out in https://github.com/JuliaLang/julia/pull/62221. I still need a good (ergonomic) way of constructing the new syntax type.
Last updated: Aug 10 2026 at 05:52 UTC