1. 27

  2. 15

    I was hoping for something else from this.

    Given the title, I was hoping for a deep insight into the tradeoffs of macros and why those tradeoffs are worthwhile in Rust. Instead, its more of a listing of “things you can do with Rust macros”. There’s nothing wrong with that.

    I’d really love to see a deep pros/cons of macros in Rust. There probably aren’t many people who could write what I’d like to see though. You’d need a deep understanding of macros across a variety of languages, a strong grounding in programming language theory, and a strong grounding in Rust.

    1. 10

      Rust’s macros currently don’t really work nicely with the module system - they all live in a global namespace and you have to use the odd #[macro_use] and #[macro_export] attributes to import and export them. It’s quite ugly. This will be fixed in Macros 2.0 though - from what I understand they are learning from Racket - I think it might be called ‘staged macro compilation’ or something… it is a non-trivial problem to solve though. Also, macros at the top level are not hygenic, I think this will also be fixed in Macros 2.0.

      Another annoyance is the APIs surrounding procedural macros - it’s not as nice as working with Racket-style reader macros. You’re more working with a token stream, rather than an AST. Also, the API does not enforce hygiene as far as I know. Again, this should also be fixed in Macros 2.0.

      Another frustration is that they don’t work nicely with rustfmt - because rustfmt doesn’t really know how the original macro author wanted to format them.

      Other issue is that they have a restricted syntax that doesn’t allow you to create really nice looking language extensions. So a match! replacement would have to look like:

      my_match!{ expr;
          pattern1 => expr1,
          pattern2 => expr2,

      Rather than:

      my_match! expr {
          pattern1 => expr1,
          pattern2 => expr2,

      This is because we want tooling to have to understand macros in order to parse Rust code. I don’t think there is any solution for this.

      All in all, I think macros a a nice addition to Rust, but they still feel a little ‘bolted on’ to the language, and could do with some improvement in the future. The Rust team knows this, and they are working hard to make those improvements!

      1. 1

        Thanks @brendan!

        1. 5

          No worries! I’m not super up-to-speed with macro theory, alas. But here are some RFCs (alas no prior art or references to the literature are given):

      2. 5

        This comment is a pretty good rundown of issues with the current macro approach.

        The list is pretty good, I’d only add the call-site syntax (!) to the list of problems.

        1. 2

          Just something I’ve observed, some of the popular languages are either strongly typed but have macros, or loosly typed and don’t have macros. ie. C/C++ vs Javascript. However, Java is strongly typed but doesn’t have macros, so take my observation with a grain of salt :)

          1. 7

            My intuition is that everybody hates boiler-plate, but static languages tend to the problem with macros, while dynamic languages address the problem with reflection and runtime meta-programming.

            Java is a notable outlier in that it addresses the boiler-plate problem with IDEs.

            1. 1

              “Java is a notable outlier in that it addresses the boiler-plate problem with IDEs.”

              Smalltalk partly solved boilerplate with the IDE and live coding. In Java ecosystem, boilerplate was the solution to C/C++‘s problems. The IDE’s then ensure that various modules have correct amounts and types of boilerplate. Or something like that.

            2. 1

              Haskell has no macros but Scheme does. Anyway, strong typing prohibits runtime type inspection and this leads to some repetitive boilerplate code, for example to derive serialisation code from type declarations. Macros can make this simpler. In the case of type-driven code, type classes (Haskell) are powerful enough to not require macros. Another case for macros is code instrumentation and here I believe type classes would not be enough.

              1. 5

                Haskell does have macros - they’re called (somewhat confusingly) ‘Template Haskell’. I prefer type-directed code generation using type classes, but this is often at the expense of compilation time, when compared to Template Haskell. Hopefully this will be improved at some stage…

                1. 1

                  Where are you putting TemplateHaskell in this categorization? I believe it’s the recommended way to handle lenses, and is also used in the Yesod ecosystem.