Elixir macros are like sugar: Just have a little

Posted July 20th, 2016 by Samuel Seay


As I've been exploring the world of macros in Elixir I've been impressed with their power and I've also been impressed by the lengths that have been taken to make macros safer to use (hygenic). I think the design decisions around macros are really solid.

Another thing I really appreciate is how every book (e.g. Metaprogramming Elixir) or article I've read warns you repetitively about macros, reminding you that they are powerful, but with great power comes great responsibility. Use them sparingly!

Much like in the Ruby world of meta programming, these techniques can be abused and overused. When you're writing code that generates code you are hiding a lot from the developer who uses your library. If things go wrong it can lead to confusing errors.

The other thing I've noticed is if you sprinkle enough macro libs together, they don't always play well together. Take this github issue for example. This particular issue highlights to me a specific danger in macros: module context.

What the writer of the tests in that issue didn't know was that every time they wrote a describe or context using Pavlov that it would generate an inline module so they were in a different context and calling use_casette failed in that context.

I recently wrote a little Elixir library myself that uses macros to generate a DSL but more specifically also generates inline modules and the user may not be aware of that when using it! If the user was to combine other macros with it, I'm not certain it would work in every situation.

You could ask why the author chose to define modules, instead of perhaps just making their library a set of functions you could import. I'm sure the author had their reasons. (I'm pretty convinced my own library needs generated modules!) But there is inherent danger in doing it, so I'll definitely be looking at ways to avoid that in future Elixir code I write.