Stream: helpdesk (published)

Topic: __source__ decaying to 'nothing' after macro expansion?


view this post on Zulip iago-lito (Jul 30 2026 at 16:48):

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?

view this post on Zulip iago-lito (Jul 30 2026 at 16:49):

(tried a = deepcopy(__source__) with no success)

view this post on Zulip iago-lito (Jul 30 2026 at 16:55):

(ended up just collecting the desired (; file, line) = __source__ instead with no problem, just curious why this happens)

view this post on Zulip Mason Protter (Jul 30 2026 at 16:56):

I think it's that lowering strips line number nodes out of code.

view this post on Zulip iago-lito (Jul 30 2026 at 16:56):

Oh, by replacing them with nothing :)

view this post on Zulip iago-lito (Jul 30 2026 at 16:57):

That makes sense. I just need to protect it from stripping somehow then.

view this post on Zulip iago-lito (Jul 30 2026 at 16:57):

Yup: a = Ref(__source__) does the trick :)

view this post on Zulip iago-lito (Jul 30 2026 at 16:58):

Thanks <3

view this post on Zulip Mason Protter (Jul 30 2026 at 16:58):

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
))))

view this post on Zulip Mason Protter (Jul 30 2026 at 16:59):

iago-lito said:

Yup: a = Ref(__source__) does the trick :slight_smile:

You can use QuoteNode for this too

view this post on Zulip iago-lito (Jul 30 2026 at 16:59):

Or just (__source__,).. really anything.

view this post on Zulip Mason Protter (Jul 30 2026 at 16:59):

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 =#

view this post on Zulip Mason Protter (Jul 30 2026 at 17:00):

QuoteNode IMO is the preferred mechanism, because it's like how you'd put a literal symbol in generated code

view this post on Zulip iago-lito (Jul 30 2026 at 17:00):

Ok. What's the difference with Meta.quot?

view this post on Zulip Mason Protter (Jul 30 2026 at 17:01):

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

view this post on Zulip iago-lito (Jul 30 2026 at 17:02):

Oh I see: https://docs.julialang.org/en/v1/manual/metaprogramming/#man-quote-node.

view this post on Zulip Mason Protter (Jul 30 2026 at 17:04):

I never really got the difference tbh. Never needed Meta.quot

view this post on Zulip iago-lito (Jul 30 2026 at 17:04):

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))))

view this post on Zulip iago-lito (Jul 30 2026 at 17:05):

It is even more litteral :P

view this post on Zulip iago-lito (Jul 30 2026 at 17:06):

Honestly I am finding that julia macro system is by far the most ergonomic and sophisticated I know.

view this post on Zulip iago-lito (Jul 30 2026 at 17:07):

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

view this post on Zulip iago-lito (Jul 30 2026 at 17:07):

(or maybe I should move that to #appreciation? ;)

view this post on Zulip Mason Protter (Jul 30 2026 at 17:19):

yeah it's quite good

view this post on Zulip Mason Protter (Jul 30 2026 at 17:19):

the new macro system being developed seems quite neat too

view this post on Zulip Mason Protter (Jul 30 2026 at 17:22):

https://github.com/JuliaLang/julia/tree/master/JuliaLowering#problems-with-hygiene-in-julias-exiting-macro-system

view this post on Zulip Notification Bot (Jul 30 2026 at 22:51):

This topic was moved here from #general > __source__ decaying to 'nothing' after macro expansion? by Mason Protter.

view this post on Zulip Notification Bot (Jul 31 2026 at 09:11):

This topic was moved here from #helpdesk > __source__ decaying to 'nothing' after macro expansion? by Mason Protter.

view this post on Zulip Em (Aug 03 2026 at 06:32):

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