…or another reason not to use macros
This is an article about something I showed live at the Erlang & Elixir Factory San Francisco 2017. It’s about what you can and can not do if you are fancy with your module attributes in Erlang.
Notes
First of all, Federico: sorry for stealing your name. It was just too cool not to ;)
That said, here is the video of the whole talk, in case you want to watch it…
And if you prefer Spanish…
Ok, enough with the links! Let’s get down to business…
The Usual Suspects
This is a perfectly valid Erlang module:
-module(my_mod).
-export([whoami/0]).
-spec whoami() -> atom().
whoami() -> my_mod.
You can compile it and execute its function…
1> c(my_mod).
{ok,my_mod}
2> my_mod:whoami().
my_mod
3>
This is also a perfectly valid Erlang module (now using a macro):
-module(my_mod).
-export([whoami/0]).
-spec whoami() -> atom().
whoami() -> ?MODULE.
As expected, same results…
1> c(my_mod).
{ok,my_mod}
2> my_mod:whoami().
my_mod
3>
The Cool Guy
But… that spec attribute there has no parentheses around it. Can we also remove the parentheses around the other attributes? The docs are not very clear about that. They show the following general syntax for attributes:
-Tag(Value).
But then there are attributes like spec, type or callback that are shown without parentheses. So, why not give it a try? How much nicer would that export be without the parentheses around the brackets, right?
-module my_mod.
-export [whoami/0].
-spec whoami() -> atom().
whoami() -> my_mod.
It actually works!! Look at that…
1> c(my_mod).
{ok,my_mod}
2> my_mod:whoami().
my_mod
3>
I’m not writing a parentheses there anymore!
Not so Fast, Cowboy!
Well… I’m not a fan of macros, but sometimes I end up using the predefined ones, like I did with ?MODULE *above…*
-module my_mod.
-export [whoami/0].
-spec whoami() -> atom().
whoami() -> ?MODULE.
Now if you try to compile that module, you’ll find quite an unexpected result…
1> c(my_mod).
my_mod.erl:5:
my_mod.erl:2: function whoami/0 undefined
my_mod.erl:4: spec for undefined function whoami/0
error
What’s going on here?
This time I literally have no clue. I can see that, in order to use the macro ?MODULE you have to use parentheses around your module name. But I haven’t done any research to find the root cause of it. That’s mostly because I have a very distinctive feeling that it will take me to the land of parsers, compilers, etc. and that’s a place I like to stay away from.
So, for this article, dear reader, if you are brave enough to go deep into the realm of the Erlang compiler and its friends and find out what’s going on, please let me know in the comments below.
And of course, if you can go ahead and fix this by sending a Pull Request to erlang/otp…
This article was first published in Erlang Battleground as Unbalanced Parentheses.
Top comments (0)