4 Macros
Macros in Erlang are written with the following syntax:
-define(Const, Replacement). -define(Fun(Var1, Var2,.., Var), Replacement).Macros are expanded when the syntax
?MacroName
is encountered.Consider the macro definition:
-define(timeout, 200).The expression
?timeout
, which can occur anywhere in the code which follows the macro definition, will be replaced by200
.Macros with arguments are written as follows:
-define(macro1(X, Y), {a, X, b, Y}).This type of macro can be used as follows:
bar(X) -> ?macro1(a, b), ?macro1(X, 123)This expands to:
bar(X) -> {a,a,b,b}, {a,X,b,123}.4.1 Macros and Tokens
Macro expansion works at a token level. We might define a macro as follows:
-define(macro2(X, Y), {a,X,b,Y).The replacement value of the macro is not a valid Erlang term because the closing right curly bracket is missing.
macro2
expands into a sequence of tokens{
,a
,X
which are then pasted into the place where the macro is used.We might use this macro as follows:
bar() -> ?macro2(x,y)}.This will expand into the valid sequence of tokens
{a,x,y,b}
before being parsed and compiled.
It is good programming practise to ensure that the replacement text of a macro is a valid Erlang syntactic form.
4.2 Pre-Defined Macros
The following macros are pre-defined:
?MODULE
.- This macro returns the name of the current module.
?MODULE_STRING
.- This macro returns the name of the current module, as a string.
?FILE
.- This macro returns the current file name.
?LINE
.- This macro returns the current line number.
?MACHINE
.- This macro returns the current machine name,
'BEAM'
,4.3 Stringifying Macro Arguments
The construction
??Arg
for an argument to a macro expands to a string containing the tokens of the argument, similar to the#arg
stringifying construction in C. This was added in Erlang 5.0 (OTP R7A).Example:
-define(TESTCALL(Call), io:format("Call ~s: ~w~n", [??Call, Call])). ?TESTCALL(myfunction(1,2)), ?TESTCALL(you:function(2,1)).results in
io:format("Call ~s: ~w~n",["myfunction ( 1 , 2 )",m:myfunction(1,2)]), io:format("Call ~s: ~w~n",["you : function ( 2 , 1 )",you:function(2,1)]).4.4 Flow Control in Macros
The following macro directives are supplied:
- -undef(Macro).
- Causes the macro to behave as if it had never been defined.
- -ifdef(Macro).
- Do the following lines if
Macro
is defined.- -ifndef(Macro).
- Do the following lines if
Macro
is not defined.- -else.
- "else" macro
- -endif.
- "endif" macro.
The conditional macros must be properly nested. They are usually grouped as follows:
-ifdef(debug) -define(....) -else -define(...) -endifThe following example illustrates this grouping:
-define(debug, true). -ifdef(debug). -define(trace(Str, X), io:format("Mod:~w line:~w ~p ~p~n", [?MODULE,?LINE, Str, X])). -else. -define(trace(X, Y), true). -endif.Given these definitions, the expression
?trace("X=", X).
in line 10 of the modulefoo
expands to:io:format("Mod:~w line:~w ~p ~p~n",[foo,100,"X=",[X]]),If we remove the
-define(debug, true).
line, then the same expression expands totrue
.4.5 A Macro Expansion Utility
The following code can be used to expand a macro and display the result:
-module(mexpand). -export([file/1]). -import(lists, [foreach/2]). file(File) -> case epp:parse_file(File ++ ".erl", [],[]) of {ok, L} -> {ok, Stream} = file:open(File ++ ".out", write), foreach(fun(X) -> io:format(Stream,"~s~n",[erl_pp:form(X)]) end, L), file:close(Stream) end.Alternatively, we can compile the file with the
'P'
option.compile:file(File, ['P'])
produces a list fileFile.P
, in which the result of any macro expansions can be seen.