Macro definition
Note that this is a new definition since Som v.3.1. See the old definition (since som v.1.5) here.
To reduce the overhead of a function call, a function can be defined as
a "macro". A macro definition is just like a function definition,
the difference is that the body of a macro definition is
substituted into the call. It is done by textual substitution (similar
to macro language). Hence, the size of a program with a
macro is larger than with a function (which is reused). The
advantage is that the program will be executed
faster. The syntax of a macro definition is similar to a function
definition, only the keyword is ":" instead of "to". For example,
:
print x = syscall {1 x}
Whenever the macro appears in the program, the macro body is
substituted.
to
report a b =
...
print a
...
will become
to
report a b =
...
syscall {1 a}
...
Macro is suitable for defining "access function" such as,
(from
list-s.txt in Som v2 som-in-som)
to setcar a value = cell[a] =
value
to setcdr a value = cell[a+1] =
value
to car a = if a == NIL a else
cell[a]
to cdr a = if a == NIL a else
cell[a+1]
These functions will be executed much faster because there is no
overhead associated with "call" "return" such as create/destroy the
stack frame.
Sometimes the use of macro can create a new control flow, for example
in the library, the "short-circuit" and/or are defined :
:
or a b = if a 1 else b
: and a b = if a b else 0
These and/or evaluated their arguments just enough to decide the
outcome. This is dfferent from the use of "&" and "|" which
always evaluate both of their arguments. (see example in the
"test" directory of somv15.zip, the file "queen2.txt").
Previously, (since som v.1.5) there are two kinds of macro, one is what
presented here. The other is called a "full" macro which evaluate
its arguments, like a function call. See
the old definition here. However, now I adopt only the
current definition, the full macro is eliminated from the
language. The discussion below described the reasoning behind
this decision.
Discussion
After a careful inspection of how macro work, I found that the meaning
of a full macro is different from a normal macro. Consider this
example of swapping two variables (as in bubble sort):
to
swap ar i j | t =
t = ar[i]
ar[i] = ar[j]
ar[j] = t
it is probably called from:
swap ax a b
If swap is a full macro it will work as expect. However if it is a
normal macro it will not work at all because there is no place for the
local "t" to participate in substitution of variables. A normal
macro "swap" (as written above) will be expanded (incorrectly) to:
? = ax[a]
ax[a] = ax[b]
ax[b] = ?
where as if "swap" is written as a normal macro, it will be:
:
swap i j t =
t = i
i = j
j = t
If it is called with a supply of variables as:
swap ax[a] ax[b] c
and by "textual" substitution (which is how a normal macro is
expanded), the expanded expression will be:
c = ax[a]
ax[a] = ax[b]
ax[b] = c
which will work correctly.
The meaning of a normal macro is therefore not the same as an
expression in the language. A full macro is supposed to be the
"inline" of the expression. The meaning of a full macro is the same as
the expression in the language. So, the meaning of a full macro
and a normal macro are different. It is not good to have a syntax
construction that has two meanings in the same language. I have
to choose only one. A normal macro is simpler to compile and very
powerful. It is also proved to be much more useful (one evidence is
that the som-compiler itself never use a full macro). Therefore I
choose to adopt a normal macro and discard a full macro from the
language.
A normal macro is similar to a macro in C language as it is a textual
substitution. I have not yet pondered their differences in
full. A macro in C has been considered by many language designers
as "not recommend". An expression written in a macro in C is
different from a normal expression and can caused a subtle bug if it is
used carelessly.
last update 26 Aug 2007