Advanced Metaprogramming Uses of QuoteNode

Continuing the discussion from Is there a better way to write this macro?:

Quoth The Manual:

The parser yields QuoteNodes for simple quoted items like symbols.
QuoteNode can also be used for certain advanced metaprogramming tasks.

Has anyone encountered one of these advanced metaprogramming tasks? A QuoteNode symbol is very easy to encounter, of course:

julia> dump(:(:quoted))
QuoteNode
  value: Symbol quoted

And the manual shows a method for constructing a $ expression which won’t interpolate when evaluated.

Are there cases in Julia’s source code where QuoteNodes get used this way? Anyone out there had a use for this technique in the wild that they’d like to share?

1 Like

The Quotenode section is easier to understand when you keep in mind the preceding section on nested quotes. It may also help to point out that the counterexample in the QuoteNode section is Meta.quot(Expr(:$, :(1+2))) == :(:($(1+2))). That makes it easier to see that when evaluated, the outer quote layer is stripped away to :($(1+2)), but not really because it also interpolates to :(3) == 3. A better example would probably be :(identity( :($(1+2)) )), where it’s more apparent how fast that interpolation happens when you evaluate functions that work on expressions. In the vast majority of metaprogramming cases, you want the input expression to evaluate along with the rest of the output expression, but QuoteNode becomes useful when you are forwarding the input expression to a function working on expressions inside the output expression, really puts the meta in metaprogramming.

For an example, the macroexpand and macroexpand1 macros manually call a Quotenode before interpolating it into a macroexpand function call expression. Take @macroexpand @eval $(1 + 2): the input expression for the macroexpand macro is Expr(:macrocall, Symbol("@eval"), :(#=...=#), Expr(:$, Expr(:call, :+, 1, 2))), so far so good. You only want the @eval call to handle the interpolation in Expr(:$, Expr(:call, :+, 1, 2)), not let it occur when the macroexpand function call expression is evaluated.