Is there an equivalent to the C preprocessor directive ## in Erlang?
Let's say I want to concatenate two atom() using a -define preprocessor directive, how would I do this without having run-time side-effects?
Is there an equivalent to the C preprocessor directive ## in Erlang?
Let's say I want to concatenate two atom() using a -define preprocessor directive, how would I do this without having run-time side-effects?
i think there are not. And i think because of that you can do any this stuff at runtime without side-effects
I'm not sure I understand what you are asking but I'll take a stab at it.
-define(CATATOM(A, B), list_to_atom(list:concat(atom_to_list(A), atom_to_list(B)))).
AtomA = atom1.
AtomB = atom2.
NewAtom = ?CATATOM(AtomA, AtomB). % NewAtom is atom1atom2
or perhaps you meant this?
-define(CATATOM(A, B), AB).
NewAtom = ?CATATOM(atom1, atom2). % NewAtom is atom1atom2
although I'm not sure what use the new second would actually be. Since it would be simpler to just write atom1atom2 instead of the macro.
The second one will incur no runtime side-effects. The first will incur runtime side-effects since the result of the macro is 3 functions to run at runtime.
There is the concept of having parse transforms, that would allow you to concatenate atoms at compile time.
You can get a close enough result using parse transforms. The following parse_transform looks for "atom1 ++ atom2" and converts it to "atom1atom2" at compile time.
example module
-module(z).
-export([z/0]).
-compile({parse_transform, zt}).
z() -> concat ++ enate.
compiling with 'S' proves that it is indeed concatenated at compile time:
{function, z, 0, 2}.
{label,1}.
{func_info,{atom,z},{atom,z},0}.
{label,2}.
{move,{atom,concatenate},{x,0}}.
return.
works as expected:
1> z:z().
concatenate
the module containing the parse transform:
-module(zt).
-export([parse_transform/2]).
parse_transform(AST, _Options) ->
[parse(T) || T <- AST].
parse({function, _, _, _, _} = T) ->
erl_syntax_lib:map(fun hashhash/1, T);
parse(T) -> T.
hashhash(Tree) ->
erl_syntax:revert(
case erl_syntax:type(Tree) of
infix_expr ->
Op = erl_syntax:infix_expr_operator(Tree),
Left = erl_syntax:infix_expr_left(Tree),
Right = erl_syntax:infix_expr_right(Tree),
case {erl_syntax:operator_name(Op), erl_syntax:type(Left), erl_syntax:type(Right)} of
{'++', atom, atom} ->
erl_syntax:atom(erl_syntax:atom_literal(Left) ++ erl_syntax:atom_literal(Right));
_ ->
Tree
end;
_ ->
Tree
end
).
EDIT: edited to "overload" the infix ++ operator. Previous version used '##' function.
You can't actually do anything in a macro, it is just pure textual, well token level, substitution. N.B. you are working on the source code and not evaluating it. If you need more complex types of substitution then you need to use a parse transform.
If you write a concatenation macro you can always the ??Arg form to get the argument as a string. Look the preprocessor section of the on-line reference manual.
Of course the really interesting question is why you would want to concatenate two atoms at compile-time? I assume it is the output of another macro, otherwise there would be no point in doing it.
You mention in one of your answers that you want to parameterize modules - this can be done at run time...
The academic paper on it is here.
Mochiweb uses it.