# Static @capture instead of that of MacroTools.jl: more efficient, more functionalities, more straightforward

**URL:** https://discourse.julialang.org/t/static-capture-instead-of-that-of-macrotools-jl-more-efficient-more-functionalities-more-straightforward/20604
**Category:** Community
**Tags:** macros
**Created:** [February 9, 2019, 3:09pm UTC](https://discourse.julialang.org/t/static-capture-instead-of-that-of-macrotools-jl-more-efficient-more-functionalities-more-straightforward/20604 "2019-02-09T15:09:14Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![thautwarm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thautwarm/32/37760_2.png) [@thautwarm](https://discourse.julialang.org/u/thautwarm)
#### Post date: [February 9, 2019, 3:09pm UTC](https://discourse.julialang.org/t/static-capture-instead-of-that-of-macrotools-jl-more-efficient-more-functionalities-more-straightforward/20604/1 "2019-02-09T15:09:14Z")

</div>

To leverage [MLStyle.jl](https://github.com/thautwarm/MLStyle.jl)’s high performance, we’ve demonstrated an implementation of `@capture` with few codes, to replace that(@capture) of [MacroTools.jl](https://github.com/MikeInnes/MacroTools.jl).

> **[GitHub - thautwarm/MLStyle-Playground: Examples for MLStyle.jl](https://github.com/thautwarm/MLStyle-Playground#statically-capturing)**
>
> Examples for MLStyle.jl. Contribute to thautwarm/MLStyle-Playground development by creating an account on GitHub.

```julia
@info @capture f($x) :(f(1))
# Dict(:x=>1)

destruct_fn = @capture function $(fname :: Symbol)(a, $(args...)) $(body...) end

@info destruct_fn(:(
    function f(a, x, y, z)
        x + y + z
    end
))

# Dict{Symbol,Any}(
# :args => Any[:x, :y, :z],
# :body=> Any[:(#= StaticallyCapturing.jl:93 =#), :(x + y + z)],
# :fname=>:f
# )

```

We don’t have a plan to make a new MacroTools.jl, but we do hope that the author of MacroTools.jl can pay necessary attention to MLStyle.jl’s [expr patterns](https://thautwarm.github.io/MLStyle.jl/latest/syntax/pattern/#Expr-Pattern-1) and [AST patterns](https://thautwarm.github.io/MLStyle.jl/latest/syntax/pattern/#Ast-Pattern-1).

Benchmark result: [GitHub - thautwarm/MLStyle.jl: Julia functional programming infrastructures and metaprogramming facilities](https://github.com/thautwarm/MLStyle.jl#benchmark)

---

<div class="post-metadata">

### Author: ![improbable22](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/improbable22/32/5464_2.png) [@improbable22](https://discourse.julialang.org/u/improbable22)
#### Post date: [February 9, 2019, 7:19pm UTC](https://discourse.julialang.org/t/static-capture-instead-of-that-of-macrotools-jl-more-efficient-more-functionalities-more-straightforward/20604/2 "2019-02-09T19:19:52Z")

</div>

Could you summarise briefly what this is for? Do you have applications in mind for which the speed of `@capture` from MacroTools is a bottleneck?

---

<div class="post-metadata">

### Author: ![thautwarm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thautwarm/32/37760_2.png) [@thautwarm](https://discourse.julialang.org/u/thautwarm)
#### Post date: [February 10, 2019, 3:12am UTC](https://discourse.julialang.org/t/static-capture-instead-of-that-of-macrotools-jl-more-efficient-more-functionalities-more-straightforward/20604/3 "2019-02-10T03:12:30Z")

</div>

> Could you summarise briefly what this is for?

A brief summary is, we hope MacroTools.jl could use MLStyle.jl to achieve such a `@capture`.

AYC, currently, MacroTools.jl’s `@capture` uses underscore to denote the variables to be capture, e.g., `struct typename_ fields__ end`, which is quite an inconsistent notation that makes many people including me feel uncomfortable. Although there is a background about why don’t use `$`,

> <https://github.com/JuliaLang/julia/issues/12102>
>
> Proposal: I'd like to incorporate some form of pattern matching for expressions,… in particular \[ExpressionMatch.jl\](https://github.com/one-more-minute/ExpressionMatch.jl). I'd love for the macro-writers among you to give feedback and help me hash out the API and implementation.
> \## Why \`@match\`
> 
> Working with Julia \`Expr\` objects is a pain, requiring an encyclopedic knowledge of implementation details to do the right thing and handle strange edge cases. Pattern matching provides an answer: expressions are described as they are written, so you don't have to remember two representations of everything.
> 
> @tkelman points out:
> 
> \> Code that uses pattern matching looks neat, but to me it comes across as a bit of a too-clever novelty syntax pun, and people who've never seen or used pattern matching before (which I'll postulate is the vast majority of Julia users) are going to have a really hard time understanding what's going on.
> 
> I think this is a very fair point, and if we were talking about implementing pattern matching over general Julia types I might agree. But working with expressions already has a learning curve above and beyond general types; in order to read or write a macro one must know or work out how every type of expression is internally specified. And that's before you get to the confusing details like the difference between \`Expr(:quote, :x)\` and \`QuoteNode(:x)\` (can you remember which is created by \`:(Foo.bar)\` and \`@m(Foo.bar)\`, I wonder?), which expressions create extraneous \`begin\` blocks for a single element, etc. etc. I've written a ton of macros and these things still trip me up every time – people who haven't spent years banging their heads against \`Expr\` objects (which I'll postulate is the vast majority of Julia users) are going to have a really hard time understanding what's going on.
> 
> Consider the readme example:
> 
> \`\`\` julia
> julia\> ex = quote
> type Foo
> x::Int
> y
> end
> end
> 
> julia\> if isexpr(ex.args\[2\], :type)
> (ex.args\[2\].args\[2\], ex.args\[2\].args\[3\].args)
> end
> (:Foo,{:( # line 3:),:(x::Int),:( # line 4:),:y})
> 
> julia\> @match ex begin
> type T\_
> fields\_\_
> end -\> (T, fields)
> end
> (:Foo,{:(x::Int),:y})
> \`\`\`
> 
> \`@match\` is probably a bit surprising the first time you see it, but that's a one-off cost – it only has to click once and you understand it every time it's used. The \_syntax\_ \`x.args\[2\].args\[3\].args\` may not surprise you initially, but what about its intent? You have to wade through it every time you see it.
> 
> Hell, you've only seen it once, and I'll bet you find it much easier to see what's going on \[here\](https://github.com/JuliaLang/julia/blob/7682f9131a875b99db742732da4255ef44335cfd/base/docs/Docs.jl#L275-L306) than \[here\](https://github.com/JuliaLang/julia/blob/e3dfa5678bd801a2f704f491db57c4416856a846/base/docs/Docs.jl#L290-L323). The former adds new features and handles a bunch of edge cases better – can you tell me which ones? (30 seconds, go!) Of course, it's \_possible\_ to read it in the same way it's \_possible\_ to read assembly code, but that doesn't mean we have to work with it.
> 
> This is a tradeoff, like any other design decision, but it's clear to me at least which side I'd rather be on. If you had to remember how a sparse matrix was implemented every time you used it, we'd never settle for it.
> \## The Case for Base
> 
> The doc system snippet above is the shining example of a use case of this, because we want to dispatch on a bunch of different syntax. Checking for things like \`:(:(Base.@time))\` (yes, double-quoted – how is that represented internally again?) and getting the edge cases right is a nightmare. With \`@match\`, it's crystal clear what is and isn't supported by \`@doc\`, and you don't have to be a macro wizard to suggest or implement new ideas – the accessibility of the code is greatly improved, and it's far from a novelty trick. If people can get behind this then I imagine it wouldn't hurt to have "real" support as part of the standard library, too, and there are plenty of other cases – in Base and outside of it – where macros could be improved via this syntax.

it’s not that correct for capturing `$` expression is also very rare, so you can transform Expr(:&, arg) into something else and then perform capturing if necessary.  
The main advantages of `$` notation instead of underscore are

1. Straightforward. In the issue referred above, people think so. Julia might be the only one who’s homoiconic except Lisp idioms, which is the root reason why Julia macros work. We should follow how ASTs are inserted( `:($a + b)` ), and use this notation as how ASTs are “uninserted”/captured.

2. You can introduce other pattern matching into @capture, like type matching `struct $(typename :: Symbol) ...`, packing `[1, 2, $(a...), last]` and so on.

> Do you have applications in mind for which the speed of `@capture` from MacroTools is a bottleneck?

Usually, we don’t care about performance of the tasks that MacroTools.jl is for. Macros are often used for codegen or staging computations, and even if your macro processing is very slow, only the first time you load a module would be affected.  
However, still some scenario can be performance sensitive. Some people who prefer DSLs(domain specific languages) might use MacroTools to rewrite almost all part of the ASTs, which causes that a tiny modification on a DSL would produce totally new ASTs. In this case, MacroTools would be regarded as something like a parser, which is performance significant.

---

<div class="post-metadata">

### Author: ![datnamer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datnamer/32/3471_2.png) [@datnamer](https://discourse.julialang.org/u/datnamer)
#### Post date: [February 10, 2019, 6:15am UTC](https://discourse.julialang.org/t/static-capture-instead-of-that-of-macrotools-jl-more-efficient-more-functionalities-more-straightforward/20604/4 "2019-02-10T06:15:34Z")

</div>

@MikeInnes

---

<div class="post-metadata">

### Author: ![improbable22](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/improbable22/32/5464_2.png) [@improbable22](https://discourse.julialang.org/u/improbable22)
#### Post date: [February 10, 2019, 9:09am UTC](https://discourse.julialang.org/t/static-capture-instead-of-that-of-macrotools-jl-more-efficient-more-functionalities-more-straightforward/20604/5 "2019-02-10T09:09:12Z")

</div>

OK, thanks for the explanation!

I had no idea re-useing interpolation syntax for pattern matching was a common desire — I assumed the underscores came from Mathematica (including `i_Int` etc.) and quite like the lack of clutter.

Did you find a way around the issues with parsing differences ([this comment](https://github.com/JuliaLang/julia/issues/12102#issuecomment-120562151))?

My guess is that changing MacroTools is very unlikely, as this would break every single package using it. It might be a good idea to use a different names, to make it easier for anyone to add this package & change uses one by one (or only change new code).

Edit: wait is `@capture` defined, or is this a suggestion to rename something which is defined? First playground example:

```julia
julia> using MLStyle
julia> @info @capture f($x) :(f(1))
ERROR: LoadError: UndefVarError: @capture not defined

```

---

<div class="post-metadata">

### Author: ![thautwarm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thautwarm/32/37760_2.png) [@thautwarm](https://discourse.julialang.org/u/thautwarm)
#### Post date: [February 10, 2019, 11:46am UTC](https://discourse.julialang.org/t/static-capture-instead-of-that-of-macrotools-jl-more-efficient-more-functionalities-more-straightforward/20604/6 "2019-02-10T11:46:20Z")

</div>

Hey, friend, I agree with you at all.  
The workaround of parsing issues could be solved with rewriting all `Expr(:$, args...)` into something without `$` like `Expr(a_symbol, args...)` where `a_symbol` is a Symbol not used as keywords like `let, function` and so on.  
In terms of your codes that throws `UnderVarError`, I’d say sorry to you for you might get confused about my README.

`@capture` is not defined in the MLStyle.jl, but there are several implementations as tutorials of MLStyle.jl.

- [Regex-Style](https://github.com/thautwarm/MLStyle-Playground/blob/master/StaticallyCapturing.jl)
- [RAII-Style](https://thautwarm.github.io/MLStyle.jl/latest/tutorials/capture/)

---

<div class="post-metadata">

### Author: ![thautwarm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thautwarm/32/37760_2.png) [@thautwarm](https://discourse.julialang.org/u/thautwarm)
#### Post date: [February 10, 2019, 1:47pm UTC](https://discourse.julialang.org/t/static-capture-instead-of-that-of-macrotools-jl-more-efficient-more-functionalities-more-straightforward/20604/7 "2019-02-10T13:47:32Z")

</div>

Oh, I didn’t refer to correct comment.  
If you want to capture that, in MLStyle.jl, you should this notation: `struct $T; $(_...) end`.  
You should remember MLStyle.jl provides the way to destructure ASTs just as how they’re written by humans.

---

<div class="post-metadata">

### Author: ![MikeInnes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikeinnes/32/3656_2.png) [@MikeInnes](https://discourse.julialang.org/u/MikeInnes)
#### Post date: [February 11, 2019, 1:56pm UTC](https://discourse.julialang.org/t/static-capture-instead-of-that-of-macrotools-jl-more-efficient-more-functionalities-more-straightforward/20604/8 "2019-02-11T13:56:26Z")

</div>

Neat stuff! I assume you are compiling the template to get specialised matching code. The main reason MacroTools didn’t do this originally is that (a) performance inside a macro is not that big of a deal and (b) it’s occasionally useful to match against runtime expressions, rather than literal ones. (a) could certainly change as we use `Expr` for more things. (b) isn’t necessarily a huge deal breaker but it’s useful to be aware of.

---

<div class="post-metadata">

### Author: ![thautwarm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thautwarm/32/37760_2.png) [@thautwarm](https://discourse.julialang.org/u/thautwarm)
#### Post date: [February 11, 2019, 6:23pm UTC](https://discourse.julialang.org/t/static-capture-instead-of-that-of-macrotools-jl-more-efficient-more-functionalities-more-straightforward/20604/9 "2019-02-11T18:23:11Z")

</div>

Understood.  
In fact I haven’t taken (b) into consideration. If we want to use a runtime expression as the template, it might be some cases that the template wouldn’t be used many times. It’s worth to compile the template only if the matching code is hot. You’re right.

However I’d still suggest to update the syntax of @capture, this is the motivation of some contributor of MLStyle.jl.  
If people can do capturing just as the inverse operation of AST interpolation, things could be then much easier.
