Chapter 10

Macros

Hygiene

Dylan macros are always hygienic. The basic idea is that each named value reference in a macro expansion means the same thing as it meant at the place in the original source code from which it was copied into the macro expansion. This is true whether that place was in the macro definition or in the macro call. Because a macro expansion can include macro calls that need further expansion, named value references in one final expansion can come from several different macro definitions and can come from several different macro calls, either to different macros or—in the case of recursion—distinct calls to the same macro.

(Sometimes the property that variable references copied from a macro call mean the same thing in the expansion is called hygiene and the property that variable references copied from a macro definition mean the same thing in the expansion is called referential transparency. We include both properties in the term hygiene.)

Specifically, a macro can bind temporary variables in its expansion without the risk of accidentally capturing references in the macro call to another binding with the same name. Furthermore, a macro can reference module bindings in its expansion without the risk of those references accidentally being captured by bindings of other variables with the same name that surround the macro call. A macro can reference module bindings in its expansion without worrying that the intended bindings might have different names in a module where the macro is called.

One way to implement this is for each template-element that is a name, unary-operator, or binary-operator to be replaced in the macro expansion by a special token that plays the same grammatical role as the name, unary-operator, or binary-operator but remembers three pieces of information:

In general one cannot know until all macros are expanded whether a name is a bound variable reference, a module binding reference, a variable that is being bound, or something that is not a binding name at all, such as a definition modifier or an intermediate word. Similarly, one cannot know until all macros are expanded whether a unary-operator or binary-operator refers to a local binding or a module binding. Thus the information for each of those cases is retained in the special token. A named value reference and a binding connect if and only if the original names and the specific macro call occurrences are both the same. (In that case, the lexical contexts will also be the same, but this need not be checked.) A named value reference and a binding never connect if one originated in a template and the other originated in a macro call.

References in a macro expansion to element or aref created by using element reference syntax must receive similar treatment so the name element or aref gets looked up in the environment of the macro definition, not the environment of the macro call.

For purposes of hygiene, a pattern-keyword default is treated like part of a template, even though it is actually part of a pattern.

The mapping from getters to setters done by the := operator is hygienic. In all cases the setter name is looked up in the same lexical context and macro call occurrence as the getter name.

Intentional Hygiene Violation

Sometimes it is necessary for a macro to violate the hygienic property, for example to include in a macro expansion a named value reference to be executed in the lexical context where the macro was called, not the lexical context where the macro was defined. Another example is creating a local binding in a macro expansion that will be visible to the body of the macro. This feature should be used sparingly, as it can be confusing to users of the macro, but sometimes it is indispensable.

The construct ?= name in a template inserts into the expansion a reference to name, in the lexical context where the macro was called. It is as if name came from the macro call rather than from the template.

Hygiene Versus Module Encapsulation

A named value reference in a macro expansion that was produced by a template-element that is a name, unary-operator, binary-operator, or [ templateopt ] and that does not refer to a local binding created by the macro expansion must have the same meaning as would a named value reference with the same name adjacent to the macro definition. This is true even if the macro call is in a different module or a different library from the one in which the macro definition occurs, even if the binding is not exported.

This allows exported macros to make use of private bindings without requiring these bindings to be exported for general use. The module that calls the macro does not need to import the private bindings used by the expansion.

If one of the following template-element sequences appears in the right-hand side of a rewrite rule, it may introduce named value references to the indicated name in an expansion of the macro. If such a named value reference does not refer to a local binding created by the macro expansion then it must have the same meaning as would a named value reference with the same name adjacent to the macro definition.

Items in the preceding template-element sequences have the following meanings:

Note that these template-element sequences can overlap in a template. For example { foo (bar) := } is a potential reference to foo, to foo-setter, and to bar.

Implementations must use some automatic mechanism for noting the bindings associated with the named value references in macro expansions produced by the template-element sequences described above, and must make such bindings available to any library where the macro is accessible. In general, the set of bindings that must be made available to other libraries cannot be computed precisely because the right-hand sides of rewrite rules are not fully parsed until after a macro is called and expanded, making it impossible to determine whether an occurrence of one of the described sequences of template elements will actually produce a named variable reference in the expansion. However, an upper bound on this set of bindings can be computed by assuming that all occurrences of the described template-element sequences might introduce the indicated named value reference if there is a binding for that name accessible from the module in which the macro definition appears.