Aaargh!! - Macros, Parse Transforms and others @ Erlang Battleground
Tags: erlang, compilers
Published: 2017-04-10 17:33:41

---
title: Aaargh!! - Macros, Parse Transforms and others @ Erlang Battleground
published: true
description: Not so long ago, John Hughes showed a module called Aaargh!! to the erlang-questions mailing list. How parse transforms and macros and the Erlang compiler all worked together to mess up with us.
cover_image: http://www.photos-public-domain.com/wp-content/uploads/2012/03/aaargh.jpg
tags: erlang, compilers
---

Not so long ago, [John Hughes](https://twitter.com/rjmh?lang=es) presented a module called *Aaargh!!* to the [erlang-questions](http://erlang.org/pipermail/erlang-questions/2017-January/091550.html) mailing list. He showed how parse transforms, macros and the Erlang compiler all worked together to mess up with us a bit. I’ll just present that very same story here. If you have read it already, you can safely skip the rest of the article.

##The Weird Module

This is basically the module that John sent to the mailing list (I changed its name just so it’s easier to avoid the apostrophes)…

```erlang
    -module(weird).

    -define(PLEASE_DONT).

    -ifdnef(PLEASE_DONT).
    -compile({parse_transform, undefined_parse_transform}).
    -endif.
```

The idea is that we first define the `PLEASE_DONT` macro in a line that we can later comment out if needed (or rather remove and define the macro at compile time).

Then, if the macro is **not** defined, we run the code through a parse transformation called `undefined_parse_transform`. The key point here is that this parse transformation module doesn’t exist, so this line *should* *not compile*.

But the macro *is* defined, so the parse transform should not be used, right?

```bash
    $ erlc weird.erl
    src/weird.erl: undefined parse transform 'undefined_parse_transform'
```

##And My Macro?

Turns out that macro is **not** defined. As Alex points out in the mailing list…
> #there’s no one-argument define()

As you can see in [the docs](http://erlang.org/doc/reference_manual/macros.html#id85572):
> A macro is defined as follows:
> *-define(Const, Replacement).
-define(Func(Var1,...,VarN), Replacement).*

If we change the define line in our code…

```erlang
    -module(weird).

    -define(PLEASE_DONT, true).

    -ifndef(PLEASE_DONT).
    -compile({parse_transform, undefined_parse_transform}).
    -endif.
```

…it compiles perfectly:

```bash
    $ erlc weird.erl
    $ ls weird.beam
    weird.beam
```

##Why didn’t you tell me so?

That’s it, right? Well… not so easy. If there is no one-argument define(), then why did the compiler/parser not warned us about it. Check this out:

```erlang
    -module(weird).

    -define(PLEASE_DONT).
```

If we try to compile that module…

```bash
    $ erlc weird.erl
    src/weird.erl:3: badly formed 'define'
```

##What’s going on here?

What we have here are two different kinds of *compilation* errors:

* badly formed ‘define’ attributes

* inexistent parse transformations

We only see one of them because they are found in different stages of the compilation process. To understand this a little bit better you’ll find a video of a talk by [Richard Carlsson](https://medium.com/@carlsson.richard) that deals with the compiler and its friends in a lot of detail below. But in a nutshell: For the *parser*, one-argument defines (or any other attribute declarations, for what is worth) are perfectly valid even when it does recognize macro definitions, but missing parse transformation modules are not. The *compiler* is the one that detects one-argument defines as errors. The *parser* is executed before the *compiler* and between those two, only the first one that finds an error, gets to shout about it ;)

That’s why when the define is broken, the *parser* ignores it and proceeds until it finds a missing parse transformation module and then it emits the error and stops the process. But when the parser finds no problems (i.e. there is no missing parse transformation module, in our case), then the *compiler* is executed, it finds the one-argument define and fails.

******

##Bonus Track

After this whole conversation in erlang-question there was just one extra question in my mind:
> If there’s no one-argument define(), what happens if I define a macro in the command line, then?

To test that, I created this module:

```erlang
    -module(weird).

    -export([macro/0]).

    macro() -> ?THE_MACRO.
```

I can totally compile the module and specify a value for the macro on command line, like this:

```bash
    $ erlc -DTHE_MACRO=hello weird.erl
    $
```

If I try to use it in an Erlang shell, I get the following expected result:

```erlang
    1> weird:macro().
    hello
    2>
```

Now, what happens if I don’t specify a value for the macro? [The docs](http://erlang.org/doc/man/erlc.html#id200346) are a little vague in this area

> -D<Name>
 Defines a macro.

Let’s try ourselves, shall we?

```bash
    $ erlc -DTHE_MACRO weird.erl
    $
```

Since the module did compile, the Erlang compiler should’ve assigned a value to the macro, right? Let’s see what that value is…

```erlang
    1> weird:macro().
    true
    2>
```

![I don’t know what I expected](http://i0.kym-cdn.com/photos/images/newsfeed/000/617/851/56d.gif)

*****

_This article was originally published in [Medium](https://medium.com/erlang-battleground/aaargh-a7dc940f8d0f)_