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.

Table 14-1 Definitions

Macro

Description

Page

define variable

Defines and initializes a variable binding in the current module.

374

define constant

Defines and initializes a constant binding in the current module.

375

define generic

Defines a constant binding in the current module and initializes it to a new generic function.

376

define method

Adds a method to a generic function, and potentially defines a constant binding in the current module containing a new generic function.

377

define class

Defines a constant binding in the current module and initializes it to a new class.

378

define module

Defines and names a module, describing the imports and exports of the module.

380

define library

Defines and names a library, describing the imports and exports of the library.

386

define domain

Restricts the ways in which a generic function and set of types can be extended, thereby enabling additional error checking and compiler optimization.

388

define macro

Defines a constant module binding containing a macro.

389

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 and open. These adjectives are mutually exclusive. The default is sealed. 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 argument strength:.

define generic brew (brand :: <coffee-brand>, #key strength)
                             => (coffee :: <coffee>) 

Errata: In the published book, the word permit is incorrectly used instead of recognize.

define method [Definition]


Adds a method to a generic function, and potentially defines a constant binding in the current module containing a new generic function.

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 with define 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, and open. 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 and sealed. Additional implementation-dependent slot-adjectives may be supported.

allocation

unreserved-namebnf. Supported allocations are instance, class, each-subclass, and virtual. 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 and concrete are mutually exclusive, primary and free are mutually exclusive, and sealed and open are mutually exclusive. Additional implementation-defined adjectives may be supported. See Declaring 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 and Computing 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 58

Each 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 is all, 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.
       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 and rectangles modules do not export any variables. They are presumably used to provide definitions for the variables created and exported by the graphics modules. The difference between the graphics module and the dylan-gx module is that one variable is renamed, and the dylan-gx module exports the variables that it imports from the dylan module, while the graphics 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 is all, 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.

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 governing define sealed domain and the implications of a define sealed domain definition, see Define 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.