19972009 Ericsson AB. All Rights Reserved. The contents of this file are subject to the Erlang Public License, Version 1.1, (the "License"); you may not use this file except in compliance with the License. You should have received a copy of the Erlang Public License along with this software. If not, it can be retrieved online at http://www.erlang.org/. Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Macros Joe Armstrong Bjarne Däcker 1 Bjarne DäKer 96-09-10 PA1 macros.sgml

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 by 200.

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}.
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.

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',
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)]).
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(...) -endif

The 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 module foo 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 to true.

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 file File.P, in which the result of any macro expansions can be seen.