Chapter 14
The Built-In Macros and Special Definitions
Definitions
Definitions are used to declare the overall structure of a program. They often define one or more module bindings, but do not always do so. Definitions can only appear at top level in a program. Definitions do not return values.
Macro |
Description |
Page |
---|---|---|
|
Defines and initializes a variable binding in the current module. |
|
|
Defines and initializes a constant binding in the current module. |
|
|
Defines a constant binding in the current module and initializes it to a new generic function. |
|
|
||
|
Defines a constant binding in the current module and initializes it to a new class. |
|
|
Defines and names a module, describing the imports and exports of the module. |
|
|
Defines and names a library, describing the imports and exports of the library. |
|
|
||
|
define variable
[Definition]
Defines and initializes a variable binding in the current module.
- Macro Call:
-
define
{ adjective }*variable
variables=
init - Arguments:
-
- adjective
-
unreserved-namebnf. The adjectives allowed are implementation dependent.
- variables
-
variablebnf |
(
variable-listbnf)
- init
-
expressionbnf
- Description:
-
define variable
defines variable bindings in the current module.The values returned by init are used to initialize the bindings. The first value returned is bound to the first variable, the second value to the second variable, etc. The last variable may be preceded by
#rest
, in which case it is bound to a sequence containing all the remaining values.If more than one binding is defined, the variables are enclosed in parentheses and separated by commas.
define variable *elapsed-time* = 0; define variable (*whole-part*, *remainder*) = truncate(*amount*); define variable (*first-value*, #rest *rest-values*) = get-initial-orders();
Module bindings may be specialized. This ensures that their value will always be of a given type. An attempt to initialize or assign the binding to a value not of that type will signal an error of type
<type-error>
.define variable *elapsed-time* :: <integer> = 0; define variable *front-window* :: type-union (<window>, singleton(#f)) = initial-front-window(); define variable (*whole-part* :: <integer>, *remainder* :: <real>) = truncate(*amount*);
define constant
[Definition]
Defines and initializes a constant binding in the current module.
- Macro Call:
-
define
{ adjective }*constant
constants=
init - Arguments:
-
- adjective
-
unreserved-namebnf. The adjectives allowed are implementation dependent.
- constants
-
variablebnf |
(
variable-listbnf)
- init
-
expressionbnf
- Description:
-
define constant
defines constant bindings in the current module.The values returned by init are used to initialize the constant bindings. The first value returned is bound to the first constant, the second value to the second constant, etc. The last constant may be preceded by
#rest
, in which case it is bound to a sequence containing all the remaining values.If more than one constant is defined, the constants are enclosed in parentheses and separated by commas.
define constant $start-time = get-current-time(); define constant $pi = 3.14159; define constant ($whole-pie, $piece-pie) = truncate($pi);
Module constants may be specialized. This ensures that their value is of a given type. An attempt to initialize the constant to a value not of that type will signal an error of type
<type-error>
.define constant $start-time :: <integer> = get-current-time();
A constant binding cannot be assigned a new value. However, the object that is the value of the constant binding is not necessarily itself immutable. For example, if a constant binding contains a sequence, the elements of the sequence may be settable.
define generic
[Definition]
Defines a constant binding in the current module and initializes it to a new generic function.
- Macro Call:
-
define
{ adjective }*generic
name parameter-list [ options ] - Arguments:
-
- adjective
unreserved-namebnf. The allowed adjectives are
sealed
andopen
. These adjectives are mutually exclusive. The default issealed
. Additional implementation-defined adjectives may be supported.- name
-
variable-namebnf
- parameter-list
-
(
[ parametersbnf ])
[=>
values ] - options
-
comma-property-listbnf
- values
-
variablebnf |
(
[ values-listbnf ])
- Description:
-
define generic
is used to define generic functions.It defines a constant module binding with the name name, and initializes it to a new generic function described by the adjectives, parameter-list and options.
The adjectives specify whether the generic function is sealed. A complete description of generic function sealing is given in
Declaring Characteristics of Generic Functions
on page 135.The parameter-list specifies the parameters and return values of the generic function and thereby constrains which methods may be added to it. For a complete description of these constraints, see
Parameter List Congruency
on page 93. A generic function parameter list may not include a next-method parameter, and its keyword parameters may include neither type specializers nor default initial values.The options are alternating keywords and values. No options are defined by the language. They may be supplied by individual implementations.
The following example defines a generic function of two required arguments and one return value. All methods added to the generic function must also take two arguments and return one value. The first argument will always
be specialized to a subtype of<animal>
, the second argument will always be specialized to a subtype of<number>
, and the return value will always
be specialized to a subtype of<number>
.define generic cut-hair (subject :: <animal>, new-length :: <number>) => (new-length :: <number>)
The use of the same name for a parameter and return value indicates that the parameter is returned as the value. This is only a convention; it is not enforced by the language.
The following example defines a generic function with one required parameter and one mandatory keyword parameter,
strength:
. Methods added to the generic function must have one required parameter, they must accept keyword arguments, and they must recognize the keyword argumentstrength:
.define generic brew (brand :: <coffee-brand>, #key strength) => (coffee :: <coffee>)
Errata: In the published book, the word
permit
is incorrectly used instead ofrecognize
.
define method
[Definition]
- Macro Call:
-
define
{ adjective }*method
name parameter-list
[ body ]
end
[method
] [ name ] - Arguments:
-
- adjective
-
unreserved-namebnf. The allowed adjective is
sealed
. Additional implementation-defined adjectives may be supported. - name
-
variable-namebnf
- parameter-list
-
parameter-listbnf
- body
-
bodybnf
- Description:
-
define method
creates a method and adds it to the generic function in name. If the module binding name is not already defined, it is defined as withdefine generic
. Thus,define method
will create a new generic function or extend an old one, as needed.The adjective allows a sealing declaration to be made about the generic function to which the method is added. The effect of this adjective is described in
Abbreviations for Define Sealed Domain
on page 138.The parameter-list describes the parameters and return values of the method, including their number and type. The method can be called only with arguments that match the types of the parameters, and the method will always return values in the quantity and typed declared. Methods added to a generic function must have parameter lists that are congruent with the generic function's parameter list. A complete description of parameter lists is given in
Parameter Lists
on page 84.When the method is called, new local bindings are created for the parameters, initialized to the arguments of the call. The body is then executed in the environment containing these bindings.
define method tune (device :: <radio>) => (station :: <station>) // method body goes here end method tune
define class
[Definition]
Defines a constant binding in the current module and initializes it to a new class.
- Macro Call:
-
define
{ class-adjective }*class
name(
{ superclass },
+)
{ slot-spec | init-arg-spec | inherited-slot-spec };
*
end
[class
] [ name ] - Arguments:
-
- class-adjective
-
unreserved-namebnf. The allowed adjectives are
abstract
,concrete
,primary
,free
,sealed
, andopen
. Additional implementation-dependent class-adjectives may be supported. - name
variable-namebnf
- superclass
expressionbnf
- slot-spec
{ slot-adjective }* [ allocation ]
slot
getter-name [::
type ] [ init-expression ]
{,
slot-option }*- init-arg-spec
[
required
]keyword
symbolbnf [ init-expression ]
{,
init-arg-option }*- inherited-slot-spec
inherited slot
getter-name [ init-expression ]
{,
inherited-option }*- slot-adjective
unreserved-namebnf. Supported slot-adjectives are
constant
andsealed
. Additional implementation-dependent slot-adjectives may be supported.- allocation
unreserved-namebnf. Supported allocations are
instance
,class
,each-subclass
, andvirtual
. Additional implementation-defined allocations may be supported.- getter-name
variable-namebnf
- type
operandbnf
- init-expression
=
expressionbnf- slot-option
setter-option |
init-keyword-option |
required-init-keyword-option |
init-value-option |
init-function-option |
type-option- init-arg-option
type-option |
init-value-option |
init-function-option- inherited-option
init-value-option |
init-function-option- setter-option
setter:
{ variable-namebnf |#f
}- init-keyword-option
init-keyword:
symbolbnf- required-init-keyword-option
required-init-keyword:
symbolbnf- init-value-option
init-value:
expressionbnf- init-function-option
init-function:
expressionbnf- type-option
type:
expressionbnf
- Description:
-
define class
is used to define classes.It defines a constant module binding with the name name, and initializes it to a new class.
The class-adjectives provide sealing information about the class. Among the adjectives,
abstract
andconcrete
are mutually exclusive,primary
andfree
are mutually exclusive, andsealed
andopen
are mutually exclusive. Additional implementation-defined adjectives may be supported. SeeDeclaring Characteristics of Classes
on page 134 for a complete description of these adjectives.The superclasses are the classes from which the new class directly inherits. The rules of inheritance are described in
Class Inheritance
on page 53 andComputing the Class Precedence List
on page 54.The init-expression, required-init-keyword-option, init-value-option, and init-function-option are all mutually exclusive in a single slot-spec, init-arg-spec, or inherited-slot-spec.
Each slot-spec describes a slot specification in the class. Slot specifications are described in
Slot Specifications
on page 58Each init-arg-spec describes the handling of an initialization argument specification of the class. Initialization argument specifications are described in
Initialization Argument Specifications
on page 68.Each inherited-slot-spec describes an inherited slot specification of the class. Inherited slot specifications are described in
Inherited Slot Specifications
on page 67.
define module
[Definition]
Defines and names a module, describing the imports and exports of the module.
- Macro Call:
define module
module-name
{ export-clause | create-clause | use-clause };
*
end
[module
] [ module-name ]- Arguments:
-
- module-name
-
namebnf
- export-clause
export
{ ordinary-namebnf },
*- create-clause
create
{ ordinary-namebnf },
*- use-clause
use
used-module {,
option }*- used-module
ordinary-namebnf
- option
import-option |
exclude-option |
prefix-option |
rename-option |
export-option- import-option
import: all
|{
{ variable-spec },
*}
- variable-spec
namebnf [
=>
namebnf ]- exclude-option
exclude: {
{ namebnf },
*}
- prefix-option
prefix:
string-literalbnf- rename-option
rename: {
{ namebnf=>
namebnf },
*}
- export-option
export: all
|{
{ namebnf },
*}
- Description:
-
define module
defines a module with the given name. It describes which modules are used by the module being defined, which bindings are imported from the used modules, and which bindings are exported by the module being defined.Circular use relationships among modules are not allowed. The graph of the module-uses-module relation must be directed and acyclic.
Like other definitions, module definitions are only allowed at top level. Like all constituents, module definitions are contained in a module. The names of bindings being imported and exported in a module definition refer to bindings in the module being defined and the modules being used. These are not affected by the module that contains the module definition.
There is no prohibition against macros that expand into module definitions.
- module-name is the name of the module being defined. Note that no binding is created for this name. The namespaces of modules, libraries, and bindings are distinct. The module name is scoped within the library containing the module.
- An export-clause specifies bindings that are to be exported from the module being defined. Each name is the name of one such binding. These bindings must be defined by a definition in the module being defined. It is an error if any of the bindings were imported from other modules. It is allowed for the same name to appear more than once, since this is sometimes useful for documentation purposes.
- A create-clause specifies that the named bindings are to be declared owned by and exported from the module being defined. Each name is the name of a binding to declare and export. These bindings must not be defined by a definition in the module being defined, and they must not be imported from another module. They must be defined by a definition in a module that uses the module being defined. It is allowed for the same name to appear more than once, since this is sometimes useful for documentation purposes.
- Each use-clause describes a set of bindings to be imported from another
module. There may be multiple use clauses and there may even be multiple use clauses
importing from the same module. If there are multiple use clauses importing from the
same module, the bindings imported are the sum of the binding imported by each use
clause. Because of renaming, it is possible for the same binding to be imported multiple
times under different names. This is not an error.
Within a use clause, the used-module is the name of the module being used, and the options control which bindings are to be imported from that module, whether and how they should be renamed, and whether they should be reexported from the module being defined. Each of these options applies within the scope of the particular use clause, and does not affect the behavior of other use clauses (even if the other use clauses indicate the same module). The various options may each appear no more than once in a single use clause. They may appear in any order.- An import-option describes which bindings should be imported. It can
be the name
all
, or a series of comma-delimited variable-specs enclosed in curly braces. The default isall
, indicating that all bindings should be imported. If a series of variable-specs is specified, only the indicated variables are imported. - A variable-spec is a name, or two names separated by an arrow. In the first form, the binding has the same name in the module being used and the module being defined. In the second form the binding is renamed as it is imported. The name preceding the arrow is the name of the binding in the module being used, and the name following the arrow is the name of the binding in the module being defined.
- An exclude-option indicates bindings that should not be imported
from the module being used. The default is the empty set. This option may only
specify a nonempty set if the import option is
all
. - A prefix-option indicates a prefix to be given to all binding names as they are imported. This option can be overriden for individual bindings by supplying a renaming in a rename option or import option. The default prefix option is the empty string.
- A rename-option indicates how individual bindings should be renamed as they are imported. It is a comma-delimited series of entries surrounded by curly braces. Each entry is a pair of names separated by an arrow. The name preceding the arrow is the name of the binding in the module being used, and the name following the arrow is the name of the binding in the module being defined. The default for this option is the empty set.
- An export-option indicates which imported bindings should be
reexported from the module being defined. It can be the name
all
, or a series of comma-delimited names enclosed in curly braces. Each name is the name of the binding in the module being defined as well as the name under which it will be exported. (There is no option to rename on export.) Each binding indicated must have been imported by this use clause. It is allowed for the same name to appear more than once, as this is sometimes useful for documentation purposes.all
indicates that all the bindings imported by this use clause should be exported. The default value for this option is the empty set.
- An import-option describes which bindings should be imported. It can
be the name
define module graphics use dylan; create draw-line, erase-line, invert-line, skew-line, frame-rect, fill-rect, erase-rect, invert-rect; end module graphics; define module lines use dylan; use graphics, import: {draw-line, erase-line, invert-line, skew-line}; end module lines; define module rectangles use dylan; use graphics, prefix: "graphics$", exclude: {skew-line}; end module rectangles; define module dylan-gx use dylan, export: all; use graphics, rename: {skew-line => warp-line}, export: all; end module dylan-gx;
The modules created by these module declarations would have access to bindings with the following names:
graphics draw-line erase-line invert-line skew-line frame-rect fill-rect erase-rect invert-rect plus all the bindings in the Dylan module lines draw-line erase-line invert-line skew-line plus all the bindings in the Dylan module rectangles graphics$draw-line graphics$erase-line graphics$invert-line graphics$frame-rect graphics$fill-rect graphics$erase-rect graphics$invert-rect plus all the bindings in the Dylan module dylan-gx draw-line erase-line invert-line warp-line frame-rect fill-rect erase-rect invert-rect plus all the bindings in the Dylan module
The
lines
andrectangles
modules do not export any variables. They are presumably used to provide definitions for the variables created and exported by thegraphics
modules. The difference between thegraphics
module and thedylan-gx
module is that one variable is renamed, and thedylan-gx
module exports the variables that it imports from thedylan
module, while thegraphics
module does not.
define library
[Definition]
Defines and names a library, describing the imports and exports of the library.
- Macro Call:
define library
library-name
{ export-clause | use-clause };
*
end
[library
] [ library-name ]- Arguments:
-
- library-name
-
namebnf
- use-clause
use
used-library {,
option }*- export-clause
export
{ ordinary-namebnf },
*- used-library
ordinary-namebnf
- option
import-option |
exclude-option |
prefix-option |
rename-option |
export-option- import-option
import: all
|{
{ module-spec },
*}
- module-spec
namebnf [
=>
namebnf ]- exclude-option
exclude: {
{ namebnf },
*}
- prefix-option
prefix:
string-literalbnf- rename-option
rename: {
{ namebnf=>
namebnf },
*}
- export-option
export: all
|{
{ namebnf },
*}
- Description:
-
define library
defines a library with the given name. It describes which libraries are used by the library being defined, which modules are imported from the used libraries, and which modules are exported by the library being defined.Circular use relationships among libraries are not allowed. The graph of the library-uses-library relation must be directed and acyclic.
Like other definitions, library definitions are only allowed at top level. Like all constituents, library definitions are contained in a module. The names of modules being imported and exported by a library definition do not refer to bindings, and are not affected by the environment in which the library definition occurs.
There is no prohibition against macros that expand into library definitions.
- library-name is the name of the library being defined. Note that no binding is created for this name. The namespaces of libraries, modules, and bindings are distinct. The library name is scoped along with the other library names in the program.
- An export-clause specifies modules that are to be exported from the library being defined. Each name is the name of one such module. It is an error if any of the modules were imported from other libraries. It is allowed for the same name to appear more than once, since this is sometimes useful for documentation purposes.
- Each use-clause describes a set of modules to be imported from another
library. There may be multiple use clauses and there may even be multiple use clauses
importing from the same library. If there are multiple use clauses importing from the
same library, the modules imported are the sum of the modules imported by each use
clause. Because of renaming, it is possible for the same module to imported multiple
times under different names. This is not an error.
Within a use clause, the used-library is the name of the library being used. The mechanism by which this name is associated with another library is implementation defined.
The options control which modules are to be imported from that library, whether and how they should be renamed, and whether they should be reexported from the library being defined. Each of these options applies within the scope of the particular use clause, and does not affect the behavior of other use clauses (even if the other use clauses indicate the same library). The various options may each appear no more than once in a single use clause. They may appear in any order.- An import-option describes which modules should be imported. It can
be the name
all
, or a series of comma-delimited module-specs enclosed in curly braces. The default isall
, indicating that all modules should be imported. If a series of module-specs is specified, only the indicated modules are imported. - A module-spec is a name, or two names separated by an arrow. In the first form, the module has the same name in the library being used and the library being defined. In the second form the module is renamed as it is imported. The name preceding the arrow is the name of the module in the library being used, and the name following the arrow is the name of the module in the library being defined.
- An exclude-option indicates modules that should not be imported from
the library being used. The default is the empty set. This option may only specify
a nonempty set if the import option is
all
. - A prefix-option indicates a prefix to be given to all module names as they are imported. This option can be overriden for individual modules by supplying a renaming in the rename option or import option. The default prefix option is the empty string.
- A rename-option indicates how individual modules should be renamed as they are imported. It is a comma-delimited series of entries surrounded by curly braces. Each entry is a pair of names separated by an arrow. The name preceding the arrow is the name of the module in the library being used, and the name following the arrow is the name of the module in the library being defined. The default for this option is the empty set.
- An export-option indicates which imported modules should be
reexported from the library being defined. It can be the name
all
, or a series of comma-delimited names enclosed in curly braces. Each name is the name of the module in the library being defined as well as the name under which it will be exported. (There is no option to rename on export) Each module indicated must have been imported by this use clause. It is allowed for the same name to appear more than once, as this is sometimes useful for documentation purposes.all
indicates that all the modules imported by this use clause should be exported. The default value for this option is the empty set.
- An import-option describes which modules should be imported. It can
be the name
define sealed domain
[Definition]
Restricts the ways in which a generic function and set of types can be extended, thereby enabling additional error checking and compiler optimization.
- Macro Call:
define sealed domain
generic-function(
{ type },
*)
- Arguments:
-
- generic-function
variable-namebnf
- type
expressionbnf
- Description:
-
define sealed domain
seals the specified generic-function over the domain indicated by the types. For a complete description of the rules governingdefine sealed domain
and the implications of adefine sealed domain
definition, seeDefine Sealed Domain
on page 135.- generic-function is the name of a module binding containing an explicitly defined generic function.
- Each type is an expression, the value of which must be a type. The number of types must be the same as the number of required arguments accepted by generic-function.
define macro
[Special Definition]
Defines a constant module binding containing a macro.
- Macro Call:
define macro
macro-definition- Arguments:
-
- macro-definition
-
macro-definitionbnf
- Description:
-
See Chapter 10,
Macros,
for a complete description of the macro system.Note that
define macro
is not a defining macro but a special definition. It is not named by a binding, and so it cannot be excluded or renamed using module operations.