Julia Community 🟣

melonedo
melonedo

Posted on • Updated on

Julia Interpolation Cookbook

This is a repost of the one on my own blog

Metaprogramming is one of the key features of Julia, apart from multiple dispatching. While interpolation is essential to metaprogramming in Julia, it is usually but not always intuitive, as some tricky cases are hard to search for. this post covers some of the tricky cases when interpolating exressions that I encounter.

Official manual

Although interpolation saves you from directly manupulating Expr objects that represent Julia AST, you are still expected to understand the AST underneath that Julia really understands, and to parse Expr input (MLStyles.jl and MacroTools.jl may help). In fact I often think in AST to decide what to do and code in interpolation, which is more readable.

This article only covers some corner cases, so it is expected that you read the Program representation and the Expressions and evaluation sections in the official manual about metaprogramming before reading the content below. Also, the article about Julia ASTs in the manual is a good reference when you compose Expr objects by hand.

How to do splatting interpolation?

In short, use $(exprs...). But this isn't really that easy. You must make sure splatting is interpolated in the right context, since the interpolated expressions are the same in every context.

For example, suppose exprs = (:a, :b, :c), :($(exprs...)) will result in syntax error because Julia does not understand what you want. Below is some common use cases:

julia> exprs = (:a, :b, :c)
(:a, :b, :c)

julia> :($(exprs...);) # list of expressions
quote
    a
    b
    c
end

julia> :($(exprs...),) # tuple
:((a, b, c))

julia> :(; $(exprs...)) # named tuple. (;a,b,c) is short for (a=a,b=b,c=c)
:((; a, b, c))

julia> :[$(exprs...)] # vector
:([a, b, c])

julia> :[$(exprs...);] # also vector
:([a; b; c])

julia> :[$(exprs...);;] # row vector (matrix)
:([a;; b;; c])
Enter fullscreen mode Exit fullscreen mode

Note currently keyword arguments (and named tuple) can not be constructed with interpolation unless you use the short form above, so to construct a general keyword argument, you must use the Expr way:

julia> f = :(foo(1,2))
:(foo(1, 2))

julia> insert!(f.args, 2, Expr(:parameters, Expr(:kw, :a, 3)));

julia> f
:(foo(1, 2; a = 3))
Enter fullscreen mode Exit fullscreen mode

How to include a literal Symbol in quotes?

julia> :($(Meta.quot(:a)) + b)
:(:a + b)
# or
julia> :($(QuoteNode(:a))+b)
:(:a + b)
Enter fullscreen mode Exit fullscreen mode

They do result in different ASTs, but the difference is not significant for a single symbol.

How to include a $ in quotes?

The "uninterpolated" quote $a as in :($a + b) is valid input for macros, but is not documented. Let's examine what it is first:

julia> a=1
1

# does not work
julia> :($a)
1

julia> macro dump1(ex) ex end
@dump1 (macro with 1 method)

# because `$a` is not valid expression alone
julia> @dump1 $a
ERROR: syntax: "$" expression outside quote around REPL[94]:1
Stacktrace:
 [...]

julia> macro dump2(ex) dump(ex) end
@dump2 (macro with 1 method)

julia> @dump2 $a
Expr
  head: Symbol $
  args: Array{Any}((1,))
    1: Symbol a
Enter fullscreen mode Exit fullscreen mode

So we see that $a is Expr(:$, :a).

Top comments (2)

Collapse
 
logankilpatrick profile image
Logan Kilpatrick

Hey @melonedo! Great article, if you go into the settings and edit it, you can set the "Canonical URL" which basically takes all the SEO this post gathers and sends it back to your original post.

As a side note, I think this article could benefit from setting the initial context for why I should read this. What am I going to come away learning that isn't already in the docs itself. A brief intro on the material might also be useful to convince someone they should go read the docs in the first place. Overall, great work!

Collapse
 
melonedo profile image
melonedo

Thank you for your advice! I have improved this post with it.