Dylan Reference Manual
Dylan Reference Manual
Chapter 1 Introduction 1
Background and Goals 3
Language Overview 4
Manual Notation 6
Chapter 2 Syntax 7
Overview 9
Libraries and Modules 9
Bindings 10
Macros 10
Bodies 11
Definitions 11
Local Declarations 12
Expressions 13
Statements 15
Parameter Lists 16
Lexical Syntax 16
Special Treatment of Names 19
Top-Level Definitions 20
Dylan Interchange Format 21
Naming Conventions 22
iii
Chapter 6 Functions 75
Overview 77
Parameter Lists 82
Method Dispatch 93
Operations on Functions 98
Chapter 7 Conditions 99
Background 101
Overview 103
Signalers, Conditions, and Handlers 103
iv
Exception Handling 105
Condition Messages 111
Introspective Operations 112
v
Hygiene 159
Rewrite Rule Examples 161
vi
Chapter 14 The Built-In Macros and Special Operators 359
Overview 361
Definitions 361
Local Declarations 377
Statements 382
Special Operators 397
Glossary 419
Index 431
vii
viii
P R E F A C E
ix
x
Figure 1-0
Listing 1-0
CHAPTER 1 Table 1-0
1 Introduction
Contents
Background and Goals 3
Language Overview 4
Manual Notation 6
Contents 1
2 Contents
C H A P T E R 1
Introduction 1
Introduction
Language Overview 1
Dylan is written in a very regular syntax. In addition to making the language
easier to read and write, the layered composition of the syntax supports a
macro system that is language-aware. The macro system does not simply
perform text substitution, but rather performs syntax fragment substitution.
This allows the extension of the language within bounds that are safe,
semantically well-defined, and in accord with the ‘syntactic flavor’ of the
language.
Bindings (Dylan’s analog to variables) are lexically scoped and fully resolved at
compile time. Binding names are not retained in running programs. The
module system allows bindings to be private or shared. Names can be changed
upon import to a module, so the possibility of irreconcilable name conflicts
among separately developed modules is eliminated. Modules can provide
multiple interfaces to the same code base, decreasing the chance of exposing a
client to inappropriate interfaces.
Flow of control is supported through polymorphic function calls, a variety of
conditional and iteration constructs, and a non-local transfer mechanism (with
protected regions).
All objects are first class, including numbers, classes and functions. This means
that all objects can be used as arguments to functions, returned as values,
stored in data structures, and are subject to introspection. All objects are typed,
and type-safety is guaranteed, either through compile-time or runtime type
checking. There are no facilities for deallocating objects. Objects are deallocated
automatically when they can no longer be reached by a program.
Types are used to categorize and specify the behavior of objects. An object may
be an instance of any number of types. Classes are a particular kind of type
used to define the structure and inheritance of instances. Every Dylan object is
a direct instance of exactly one class, and a general instance of that class and
each of its superclasses. The root of the class hierarchy (and of the type
hierarchy) is a class called <object>.
Values associated with an instance are stored in slots of the instance.
Classes do not define scopes for names. Names are scoped by modules and
local binding declarations.
4 Language Overview
C H A P T E R 1
Introduction
Functions are the active portions of Dylan programs. Functions accept zero or
more arguments and return zero or more values. Functions are specialized to
accept arguments of particular types, and will signal an error if they are called
with arguments that are not instances of those types. The return values of
functions are similarly type-checked.
A method is a basic unit of callable code. When a method is called, it creates
local bindings for its arguments and executes a body in the resulting
environment. A method can be called directly by a program or indirectly
through a generic function that contains it.
A generic function contains a number of methods. When a generic function is
called, it finds the methods which are applicable to the arguments, and passes
control to the most specific of those methods.
Slots are accessed through functions. This ensures that instances present an
abstract interface to their clients, which assists both in polymorphism and in
program redesign.
Sealing declarations allow the programmer to declare portions of the class
hierarchy and set of functions to be invariant. This supports the enforcement of
protocols, compile-time resolution of polymorphic behavior, and efficient inline
slot access. Portions of a program which are not sealed can be extended at run
time or by additional libraries.
Dylan includes a number of predefined libraries, including an exception
system, collections, arithmetic, higher-order functions, and introspection.
The exception system is object-based. It uses calling semantics (thereby
allowing recovery) but also provides exiting handlers.
The collection system includes a number of predefined collection classes and
operations built on a simple iteration protocol. Additional classes defined in
terms of this protocol have access to the full suite of collection operations.
Arithmetic is fully object-based and extensible.
A library of higher-order operations on functions supports function
composition.
A library of introspective functions supports the run time examination of
objects, including classes and functions.
Language Overview 5
C H A P T E R 1
Introduction
Manual Notation 1
This manual uses a small number of typographic conventions:
■ Monospaced font (courier 12) is used to indicate text which should
appear verbatim in programs.
■ Italic font is used to name parameters, placeholders for actual program text.
■ References to entries in the BNF are given the same name as in the BNF, and
are followed by a subscripted italic bnf.
■ Bold is used for the first use of terms.
■ Bold is also used for meta-syntactic punctuation, as follows:
n [ ] Contents are optional
n { } Contents appear once
n { }* Contents appear zero or more times
n { }+ Contents appear one or more times
n | A choice between the item on the left of the vertical bar and the item on
the right of the vertical bar, but not both.
If a comma appears between a right curly brace and the following asterisk or
plus-sign, it indicates that multiple occurances of the contents are separated by
a comma. There is no comma after the last occurance.
If a semicolon appears between a right curly brace and the following asterisk or
plus-sign, it indicates that multiple occurances of the contents are separated by
a semicolon. A semicolon following the last occurance is optional.
Sample Dylan code is shown in small monospaced font. When the return
value of an expression is shown, it is preceded by an ⇒.
Chapter 10, “Macros,” and Appendix A, “BNF,” each use a distinctive
notation, described at the start of the chapter and appendix.
6 Manual Notation
Figure 2-0
Listing 2-0
C H A P T E R 2 Table 2-0
2 Syntax
Contents
Overview 9
Libraries and Modules 9
Bindings 10
Macros 10
Bodies 11
Definitions 11
Local Declarations 12
Expressions 13
Statements 15
Parameter Lists 16
Lexical Syntax 16
Special Treatment of Names 19
Escaping Names 19
Function Call Shorthand 20
Top-Level Definitions 20
Dylan Interchange Format 21
Naming Conventions 22
Contents 7
8 Contents
C H A P T E R 2
Syntax 2
Overview 2
This chapter describes the syntax and structure of a Dylan program, from the
outside in. This is one of the two defining characteristics of Dylan. The other is
the set of objects on which a Dylan program operates; objects and their types
are discussed in the following chapters. This section is only an overview;
language constructs briefly mentioned here are explained in detail in later
sections. A formal specification of Dylan syntax appears in Appendix A,
“BNF.”
Overview 9
Syntax
Bindings 2
A binding is an association of a name with a value. The bindings in a module
persist for the life of the program execution. The scope of such a binding is its
module. That is, the binding is visible to all source-records in the module. A
module can export bindings and can import bindings from other modules.
Only an exported binding can be imported. A binding is visible to all
source-records in a module that imports it.
A binding may be specialized. This restricts the types of values that may be
held in the binding. An error will be signaled on any attempt to initialize or
assign the binding to a value that is not of the correct type.
A binding is either constant or variable. A constant (or read-only) binding
always has the same value. In contrast, a variable (or writable) binding can
have its value changed, using the assignment operator :=. Most bindings in a
typical Dylan module are constant.
Macros 2
A macro is an extension to the core language that can be defined by the
programmer, by the implementation, or as part of the Dylan language
specification. Much of the grammatical structure of Dylan is built with
macros. A macro defines the meaning of one construct in terms of another
construct. The original construct is the call to the macro. The replacement
construct is the expansion of the macro. The compiler processes the expansion
in place of the call.
Portions of the call to a macro are substituted into part of the macro definition
to create the expansion. This substitution preserves the meanings of names. In
other words, each name inserted into the expansion from the macro call refers
to the same binding that it referred to in the call, and each name inserted into
the expansion from the macro definition refers to the same binding that it
referred to in the definition.
10 Bindings
C H A P T E R 2
Syntax
A macro is named by a binding and thus is available for use wherever that
binding is visible. There are three kinds of macros: defining macros, which
extend the available set of definitions; statement macros, which extend the
available set of statements; and function macros, which look syntactically like
function calls but have more flexible semantics.
Bodies 2
A body is a sequence of zero or more constituents. When multiple constituents
are present, they are separated by semicolons. When at least one constituent is
present, the last constituent can optionally be followed by a semicolon; this
allows programmers to regard the semicolon as either a terminator or a
separator, according to their preferred programming style.
A constituent is either a definition, a local declaration, or an expression.
Definitions and local declarations form the structure of a program and do not
return values. In contrast, expressions are executed for the values they return
and/or the side-effects that they perform.
Definitions 2
A definition is either a call to a user-defined defining macro, a call to a built-in
defining macro, or a special definition. Typically, a definition defines a binding
in the module containing the definition. Some definitions define more than one
binding, and some do not define any bindings.
A user-defined defining macro is a macro that defines a definition in terms of
other constructs. A call to a user-defined defining macro always begins with
the word define and includes the name of the defining macro. This name
when suffixed by “-definer” is the name of a visible binding whose value is
the defining macro. The rest of the syntax of a call to a user-defined defining
macro is determined by the particular macro. Some definitions include a body.
Advanced programmers often define new defining macros as part of
structuring a program in a readable and modular way.
A built-in defining macro is like a user-defined defining macro but is specified
as part of the Dylan language. There are eight built-in defining macros:
Bodies 11
C H A P T E R 2
Syntax
Local Declarations 2
A local declaration is a construct that establishes local bindings or condition
handlers whose scope is the remainder of the body following the local
declaration.
Unlike module bindings, local bindings are established during program
execution, each time the local declaration is executed. They persist for as long
as code in their scope is active. Local bindings persist after the body containing
them returns if they are referenced by a method created inside the body and a
reference to the method escapes from the body, so that it could be called after
the body returns. Unlike module bindings, local bindings are always variable.
However, since a local binding has a limited scope, if there is no assignment
within that scope, the local binding is effectively constant.
A local binding shadows any module binding with the same name and any
surrounding local binding with the same name. The innermost binding is the
one referenced.
The name of a local binding cannot be the name of a macro.
There are three kinds of local declaration: local value bindings (let), local
method bindings (local), and condition handler establishment (let
handler).
The local value bindings construct, let, executes an expression and locally
binds names to the values returned by that expression.
12 Local Declarations
C H A P T E R 2
Syntax
The local method bindings construct, local, locally binds names to bare
methods. These bindings are visible in the remainder of the body and also
inside the methods, permitting recursion.
The condition handler establishing construct, let handler, establishes a
function to be called if a condition of a given type is signaled during the
execution of the remainder of the body or anything the body calls. The handler
is disestablished as soon as the body returns. Unlike the other two kinds of
local declaration, let handler does not establish any bindings.
Expressions 2
An expression is a construct that is executed for the values it returns and/or
the side-effects that it performs. The “active” portions of a Dylan program are
expressions. An expression is either a literal constant, a named value reference,
a function call, a unary operator call, a binary operator call, an element
reference, a slot reference, a parenthesized expression, or a statement.
An operand is a restricted expression: it cannot be a unary or binary operator
call nor a symbol literal. The other seven forms of expression are allowed.
Operands appear in situations in the grammar where an expression is desirable
but the full generality of expressions would make the grammar ambiguous.
A literal constant directly represents an object. Literal constants are available
for numbers, characters, strings, symbols, boolean values, pairs, lists, and
vectors. For example:
number 123, 1.5, -4.0, #x1f4e
character 'a', '\n'
string "foo", "line 1\nline 2"
symbol test:, #"red"
boolean value #t, #f
pair #(1 . "one")
list #(1, 2, 3)
vector #[1, 2, 3]
Expressions 13
C H A P T E R 2
Syntax
14 Expressions
C H A P T E R 2
Syntax
Statements 2
A statement is a call to a statement macro. It begins with the name of a visible
binding whose value is a statement macro. The statement ends with the word
end optionally followed by the same name that began the statement. In
between is a program fragment whose syntax is determined by the macro
definition. Typically this fragment includes an optional body. For example,
if (ship.ready?) embark(passenger, ship) end if.
A statement macro can be built-in or user-defined.
A user-defined statement macro is a macro that defines how to implement a
statement in terms of other constructs. Advanced programmers often define
new statement macros as part of structuring a program in a readable and
modular way.
A built-in statement macro is like a user-defined statement macro but is
specified as part of the Dylan language. There are nine built-in statement
macros: begin, block, case, for, if, select, unless, until, and while.
An implementation can add new kinds of statements as language extensions.
Such a statement takes the form of a user-defined statement macro that is the
value of a binding exported by an implementation-defined module.
Statements 15
C H A P T E R 2
Syntax
Parameter Lists 2
Several Dylan constructs contain a parameter list, which describes the
arguments expected by a function and the values returned by that function.
The description includes names, types, keyword arguments, fixed or variable
number of arguments, and fixed or variable number of values. The argument
names specified are locally bound to the values of the arguments when the
function is called. The value names specified are only for documentation.
The syntactic details of parameter lists are described in “Methods” on page 412.
Lexical Syntax 2
Dylan source code is a sequence of tokens. Whitespace is required between
tokens if the tokens would otherwise blend together. Whitespace is optional
between self-delimiting tokens. Alphabetic case is not significant except within
character and string literals.
Whitespace can be a space character, a tab character, a newline character, or a
comment. Implementations can define additional whitespace characters.
A comment can be single-line or delimited. Although comments count as
whitespace, the beginning of a comment can blend with a preceding token, so
in general comments should be surrounded by genuine whitespace.
A single-line comment consists of two slash characters in a row, followed by
any number of characters up to and including the first newline character or the
end of the source record. For example, // This line is a kludge!.
A delimited comment consists of a slash character immediately followed by a
star character, any number of characters including balanced slash-star /
star-slash pairs, and finally a star character immediately followed by a slash
character. For example, /* set x to 3 */.
A single-line comment may appear within a delimited comment; occurances of
slash-star or star-slash within the single line comment are ignored.
16 Parameter Lists
C H A P T E R 2
Syntax
Lexical Syntax 17
C H A P T E R 2
Syntax
18 Lexical Syntax
C H A P T E R 2
Syntax
Escaping Names 2
The escape character ( \ ) followed by any name or operator-name has the
same meaning as that name or operator-name, except that it is stripped of
special syntactic properties. If it would otherwise be a reserved word or
operator, it is not recognized as such.
For example, \if and if are names for the same binding, but \if is treated
syntactically as a named value reference, while if is the beginning of a
statement. Similarly, \+ and + refer to the same binding, but the former is
treated syntactically as a named value reference, and the latter as an operator.
Syntax
For reserved words, this allows the names of statement macros to be exported
and imported from modules. It does not allow them to be used as the names of
local bindings, nor does it allow them to be executed. (That is, they cannot be
used as bindings to runtime values.)
For operators, it allows the operator to be used where a named value reference
is required, for example as the name in a method definition, as an argument to
a function, or in a define module export clause. This feature can only be
used for operators which provide a shorthand for a function call. It cannot be
used for special operators.
Top-Level Definitions 2
Dylan's built-in defining macros can only be used at top level. When the
expansion of a user-defined macro includes a call to a built-in defining macro,
the user-defined macro also can only be used at top level.
A constituent is at top level if and only if it is a direct constituent of a body, no
preceding constituent of that body is a local declaration, and the body is either
the body of a source record or the body of a begin statement that is itself a
constituent at top level. When a constituent appears inside a call to a macro,
whether that constituent is at top level must be determined after macro
expansion.
The effect of the above rule is that a constituent at top level is not in the scope
of any local declarations, is not subject to any condition handlers other than
default handlers, and is not affected by any flow of control constructs such as
conditionals and iterations. This restriction enhances the static nature of
definitions.
20 Top-Level Definitions
C H A P T E R 2
Syntax
Syntax
the code body. (A "blank line" is a line consisting of zero or more space or tab
characters, ending in a newline character.)
The following standard keywords are defined:
The source record in the file is written in the named language. The only
portable value for this keyword is infix-dylan.
The source record in the file is associated with the named module. This
keyword is required.
These are provided for standardization. They are optional, and can be ignored
by the implementation.
A typical Dylan source file might look like this:
module: quickdraw
author: J. Random Rect
Linear Wheels, Inc., "Where quality is a slogan!"
[email protected]
copyright: (c) 1995 Linear Wheels, Inc., All rights reserved
version: 1.3 alpha (not fully tested)
Naming Conventions 2
Several conventions for naming module bindings help programmers identify
the purposes of bindings. In general, the names of bindings do not affect the
22 Naming Conventions
C H A P T E R 2
Syntax
<window>
<object>
<character>
<number>
<stream>
<list>
*parse-level*
*incremental-search-string*
*machine-state*
*window-count*
$pi
$end-of-file
subclass?
even?
instance?
■ Operations that return a value similar to one of their arguments and which
also destructively modify the argument end in a !. (It will often also be the
case that destructive and non-destructive variations of the function exist.) !
isn't a universal warning that an operation is destructive. Destructive
functions that return other values (like -setter functions and pop) don't
need to use the ! convention.
reverse!
sort!
Naming Conventions 23
C H A P T E R 2
Syntax
element element-setter
size size-setter
color color-setter
24 Naming Conventions
Figure 3-0
Listing 3-0
C H A P T E R 3 Table 3-0
3 Program Structure
Contents
Modules 27
Defining Module Bindings 27
Libraries 28
Contents 25
26 Contents
C H A P T E R 3
Program Structure 3
Modules 3
Modules are used for creating large-scale namespaces of bindings. The
bindings accessible in a module are visible to all the code within the module
(except where shadowed by a local binding). Only the bindings explicitly
exported are visible from outside the module.
Some languages have module systems with distinct support for exporting
variables, functions, types, and classes. Dylan modules operate only on
bindings. Because functions and classes are commonly named by bindings,
access to them is controlled by controlling access to the bindings that name
them. By exporting the binding naming a class or function, a program has
effectively exported the class or function. If the binding is not exported, then
the class or function is effectively private.*
A module definition defines the imports and exports of a module, and may
specify bindings owned by the module. A complete description of module
definitions is given on page 369.
Modules 27
Program Structure
Libraries 3
A library consists of the following parts:
■ A library definition. This specifies a name for the library, a set of modules
which are exported from the library for use by other libraries, and a set of
modules that are imported from other libraries for use by the library being
defined. A complete description of library definitions is given on page 374.
■ The association of source code with the library. The mechanism by which
this association is made is controlled by the programming environment and
is implementation-defined.
■ The association of executable code with the library. The mechanism by
which this association is made is implementation-defined. The mechanism
by which the compiler is invoked to produce the executable code is
implementation-defined.
■ The export information of the library. The format of this information and
the mechanism by which it is associated with the library is
28 Libraries
C H A P T E R 3
Program Structure
The library export information is the only part of a Dylan library that is
needed to allow some other library to import it. A library that exports some
modules does not have any additional declarations providing information to
the compiler when it is processing the code that imports those modules.
Rather, any such information that is needed is obtained in some
implementation-defined way while processing the source code of the
exporting library and is retained in the library export information of the
exporting library.
Exporting a module from a library makes all of the bindings exported by the
module available for import by modules in other libraries.
Importing a module into a library allows the module to be used by modules
defined within the library. This gives the library’s modules access to the
bindings of the module being imported.
Importing a module into a library does not allow source records in the
importing library to be contained in the imported module.
Each implementation must provide a library named dylan which exports a
module named dylan. That module must export exactly those bindings
documented as being part of the Dylan language, and the values of those
bindings must be as specified by the Dylan language. The dylan library is
permitted to export additional implementation-defined modules.
Each library contains an implicitly defined module whose name is
dylan-user. Within this module, all the bindings specified by the Dylan
language are accessible using their specified names. Additional
implementation-dependent bindings may also be accessible from this module.
Libraries 29
C H A P T E R 3
Program Structure
30 Libraries
Figure 4-0
Listing 4-0
C H A P T E R 4 Table 4-0
4 Program Control
Contents
Overview 33
Function Calls 33
General Syntax 33
Slot Reference 34
Element Reference 35
Operators 35
Assignment 37
Conditional Execution 39
True and False 39
Iteration 40
Iteration Statements 40
Tail Recursion 40
Non-Local Exits and Cleanup Clauses 41
Multiple Values 41
Order of Execution 43
Execution Order Within Expressions 43
Contents 31
32 Contents
C H A P T E R 4
Program Control 4
Overview 4
Dylan provides a number of program control constructs, implementing
function calls, operators, assignment, conditional execution, iteration, and
non-local flow of control.
This chapter also describes the multiple-value facility and the rules for order of
execution of Dylan programs.
Function Calls 4
General Syntax 4
The general syntax for function calls is
function(arg1, arg2, … argn)
function has the syntax of an operand and is the function to be called. The args
have the syntax of expressions, and are the arguments to the function. The
function will often be a named value reference, but it can be any other kind of
operand as well.
In the following example, the function being called is the value of the binding
average.
average(x, y)
In the following two examples, the function being called is the value of a
method statement. The examples differ only in that the second example puts
parentheses around the method statement, to make the code somewhat more
readable.
Overview 33
Program Control
In the following examples, the function being called is the result of another
function call. key-test takes a collection as an argument, and returns a
predicate function. The predicate function is then applied to the two keys. The
following three program fragments will have the same effect.
key-test(collection)(key1, key2)
(key-test(collection))(key1, key2)
begin
let fun = key-test(collection);
fun(key1, key2);
end
Slot Reference 4
Dylan provides a shorthand syntax for functions which accept one argument.
The syntax argument.function applies function to argument. This syntax is
commonly used for slot reference, to access the function slot of argument.
Order of execution aside, the following pairs of function calls are equivalent:
america.capital
capital(america)
window.position
position(window)
Slot reference syntax can be cascaded and is left associative. Order of execution
aside, the following pair of expressions are equivalent. Each returns the origin
of the root-view of a window.
window.root-view.origin
origin(root-view(window))
34 Function Calls
C H A P T E R 4
Program Control
Element Reference 4
Dylan provides a shorthand syntax for element reference. The syntax
sequence[i] is equivalent to the function call element(sequence, i). The
syntax array[i1, i2, … in] is equivalent to the function call aref(array, i1, i2,
… in).
Order of execution aside, the following pairs of expressions are equivalent:
*all-windows*[0]
element(*all-windows*, 0)
*tic-tac-toe*[1, 2]
aref(*tic-tac-toe*, 1, 2)
The names element and aref are looked up in the environment of the
element reference expression.
Operators 4
Dylan provides a small number of unary and binary operators. Three of these
are special operators with explicitly defined syntax and execution rules. The
remainder are syntactic shorthand for function calls.
Operators and their operands must be separated by whitespace or parentheses.
All binary operators are left-associative, except for the assignment operator, :=,
which is right-associative.
Each operator that is syntactic shorthand for function call corresponds to a
binding name, given in the table below. When an operator is called, the
corresponding name is looked up in the environment of the call. (It is not
looked up in the Dylan module, and will only refer to a binding in the Dylan
module if that binding has been imported in the current module and has not
been shadowed by a lexical binding.)
If the name given in the table has the same spelling as the operator, it must be
escaped with \ to be used as a named value reference. For example, to add a
method to + with define method, you use \+. To use < as an argument to
sort, you write \<.
Operators 35
C H A P T E R 4
Program Control
Special operators do not correspond to any binding name, and cannot be used
with any alternate syntax.
With the exception of calls to the three special operators (&, |, and :=), the
operands of a binary operator call are executed in left to right order. Special
operators have their own flow of control rules, described in “Special
Operators” on page 397.
The operators are listed below in descending order of precedence. Operators
within a group share the same precedence. When a function call using slot
reference syntax reference appears as an operands, it has greater precedence
than any of the binary operators.
^ binary exponentiation ^
* binary multiplication *
/ binary division /
36 Operators
C H A P T E R 4
Program Control
= binary equality =
== binary identity ==
~= binary non-equality ~=
~== binary non-identity ~==
< binary less than <
> binary greater than >
<= binary less than or equals <=
>= binary greater than or equals >=
Assignment 4
The special operator := is used to set variables to new values and as an
alternate syntax for calling setter functions and macros.
The assignment operator is described in detail on page 397.
The following examples show the use of := to change the value of a module
binding.
Assignment 37
C H A P T E R 4
Program Control
The following examples show the use of := as shorthand for calling a setter
function. In general, using this syntax to call a function fun is equivalent to
calling the function fun-setter.
The following examples show the use of := as shorthand for calling a setter
function using slot access notation.
my-vector[2] := #”two”
my-array[1,1] := #”top-left”
38 Assignment
C H A P T E R 4
Program Control
Conditional Execution 4
There are a number of statements and special operators that can be used to
conditionally execute code. These are described in detail in Chapter 14, “The
Built-In Macros and Special Operators.”
Conditional Execution 39
C H A P T E R 4
Program Control
The false object is the constant #f. There is a canonical true object, #t, which
can be used for clarity of code. #t and #f are instances of the class
<boolean>.
Because all values besides #f count as true, the term “true or false” is not
equivalent to “#t or #f”.
The special operator ~ is used for logical negation. If its operand is true, it
returns #f. If its operand is #f, it returns #t.
Iteration 4
Iteration is supported through a number of statements, as well as through
recursive functions.
Iteration Statements 4
The statemens supporting iteration are described in detail in Chapter 14, “The
Built-In Macros and Special Operators.”
Tail Recursion 4
Implementations are encouraged to optimize tail recursive function calls
whenever possible. Tail recursion occurs when a function F1 returns the values
40 Iteration
C H A P T E R 4
Program Control
of a call to another function F2. In many cases, this can be used to create loops
using self-recursive or mutually-recursive functions. (Among the cases which
cannot be optimized are those in which the return value types of F1 and F2
differ, requiring the F1 to check the types of the values before returning them.)
The following example uses tail recursion to compute the name of the root
volume on which a given file system object is stored.
The example above can execute with constant stack size, regardless of how
deeply nested the file system hierarchy may be.
Multiple Values 4
The execution of an expression can yield one value, more than one value, or no
values at all. This capability is called multiple values.
Program Control
Multiple values are generated by the function values. They are received by
the bindings of let declarations and define constant and define
variable definitions.
Many statements will return multiple values if the last expression they execute
returns multiple values. Similarly, a function will return all the values of the
last subexpression it executes.
define method return-three-values (a, b, c)
values(a, b, c)
end method return-three-values;
begin
let (foo, bar, baz) = return-three-values (1, 2, 3);
list (foo, bar, baz)
end
=> #(1, 2, 3)
Each expression in the argument list of a function call supplies only one
argument to the function call. That argument is the first value returned by the
expression. Additional values returned by the expressions are ignored.
42 Multiple Values
C H A P T E R 4
Program Control
■ If there are more bindings than there are values, the extra bindings are
initialized to #f. (If a binding is typed, #f must be an instance of its type or
an error is signaled.)
■ If there are more values returned than there are bindings, the excess values
are placed in a sequence which is used as the initial value for rest-binding or
discarded there is no rest-binding.
begin
let (one #rest nums) = return-three-values(1, 2, 3);
nums;
end
⇒ #(2, 3)
Order of Execution 4
Order of execution is defined for the constituents within a body. With some
exceptions noted below, this execution order is left-to-right.
Definitions form the overall structure of a program and are not said to execute.
In particular, module bindings are not created in any order, but all exist when
program execution commences. To the extent that these bindings must be
initialized by the values of some expressions which cannot be analyzed at
compile time, references to the bindings are constrained by the execution order
of the expressions within the surrounding body.
Dylan implementations are encouraged to allow forward references to module
bindings whenever possible.
The order of execution of the components of a call to a user-defined macro is
determined by the macro.
Order of Execution 43
C H A P T E R 4
Program Control
one.two
one[two, three]
slot-setter(one, two)
two.slot := one
44 Order of Execution
Figure 5-0
Listing 5-0
C H A P T E R 5 Table 5-0
Contents
Overview 47
The Type Protocol 47
Base Types and Pseudosubtypes 48
Type Disjointness 49
Classes 50
Features of Classes 50
Creating Classes 50
Class Inheritance 51
Computing the Class Precedence List 52
Slots 55
Slot Inheritance 57
Slot Specifications 57
Instance Creation and Initialization 63
Overview 63
Inherited Slot Specifications 66
Initialization Argument Specifications 67
Singletons 70
Union Types 71
Limited Types 72
Limited Type Constructor 72
Limited Integer Types 72
Limited Collection Types 74
Contents 45
46 Contents
C H A P T E R 5
Overview 5
The Dylan type system is used to categorize all objects. In concert with generic
functions, types determine the behavior of objects. When an object is passed as
an argument to a generic function, the generic function looks at the type of the
object to determine which method should be run.
Dylan supports several kinds of types, including classes, singletons, union
types, and limited types.
■ Classes are used to define the structure, inheritance, and initialization of all
objects. An object can be an instance of any number of types, but will
always be a direct instance of exactly one class.
■ Singletons are used to indicate individual objects.
■ Union types are used to indicate objects which are instances of one of a set of
specified types.
■ Limited types are used to indicate objects which are instances of another
type and have additional constraints. There are several kinds of limited
types.
All types are first-class objects, and are general instances of <type>.
Implementations may add additional kinds of types. The language does not
define any way for programmers to define new subclasses of <type>.
Overview 47
Type Disjointness 5
Informally, two types are disjoint if there can be no object that is an instance of
both types. Formally, the disjointness of types is specified by the following set
of rules. (Some of these rules reference definitions given in “Limited Integer
Types” on page 72, “Element Types” on page 122 and “Limited Collection
Types” on page 124.)
■ Two classes are disjoint if they have no common subclasses.
■ A union type is disjoint from another type if both of the union type's
component types are disjoint from that other type.
■ A singleton type is disjoint from another type if the singleton’s object is not
an instance of that other type.
■ A limited collection type is disjoint from a class if their base types are
disjoint, or the class is a subclass of <collection> and its element type is
definite and not equivalent to the limited collection type's element type, or
the class is a subclass of <collection> and its element type is indefinite
and not a supertype of the limited collection type's element type.
■ A limited collection type is disjoint from a limited integer type. (Because the
classes <collection> and <integer> are disjoint.)
■ Two limited collection types are disjoint if their base types are disjoint, or
their element types are not equivalent, or their sizes are not compatible.
Two sizes are compatible if either is #f, or they are = to each other, or one is
a sequence of integers and the other is the product of those integers.
■ Two limited integer types are disjoint if the minimum value of one is greater
than the maximum value for the other.
■ A limited integer type is disjoint from a class if their base types are disjoint
or the class is a subclass of <integer> whose range is disjoint from the
limited integer type’s range.
Classes 5
Classes are used to define the inheritance, structure, and initialization of objects.
Every object is a direct instance of exactly one class, and a general instance of
the general superclasses of that class.
A class determines which slots its instances have. Slots are the local storage
available within instances. They are used to store the state of objects.
Classes determine how their instances are initialized by using the initialization
protocol.
Features of Classes 5
There are four features of classes, each of which is independent of the others.
■ A class can be abstract or concrete. If the class is concrete, it can have direct
instances. If it is abstract, it cannot have direct instances, but only indirect
instances.
■ A class can be instantiable or uninstantiable. If the class is instantiable, it
can be used as the first argument to make. If it is uninstantiable, it cannot be
used as the first argument to make.
■ A class can be primary or free. This controls how a class can be used for
multiple inheritance. For a full description of this feature, see “Declaring
Characteristics of Classes” on page 132.
■ A class can be sealed or open. This controls whether a class can be
subclassed outside the library where it is defined. For a full description of
this feature, see “Declaring Characteristics of Classes” on page 132.
Creating Classes 5
New classes may be created by calling make on <class>, or with the
definition define class. In most programs the latter is more commonly
used.
50 Classes
C H A P T E R 5
When a class is created with make, it is instantiated and returned just like any
other object. The options available when creating a class with make are
described on page 186.
When a class is created with define class it is used to initialize a new
module binding. define class allows the specification of superclasses,
slots, initialization behavior, and options related to sealing. The complete
syntax of define class is given on page 366.
The following simple class definition creates a class named by the module
binding <new>. The class inherits from <object>, and does not specify any
slots.
The following class definition illustrates the creation of a class with multiple
superclasses. Again, there are no slots.
Class Inheritance 5
When a class is created, its direct superclasses are specified. The new class
directly inherits from these classes; it is a direct subclass of each of these
classes. There can be no duplicates in the direct superclasses of a class.
The subclass relationship is transitive. If a class C is a direct subclass of C1, C1
is a direct subclass of C2, and C2 is a direct subclass of C3, then C is an indirect
subclass of C2 and C3. A general subclass is a direct or indirect subclass.
Inheritance cannot be circular. A class cannot be its own general subclass.
A class is a subtype of each of its general superclasses.
Every class is a general subclass of <object>.
Classes 51
C H A P T E R 5
52 Classes
C H A P T E R 5
Classes 53
C H A P T E R 5
next-minimal-elements(remaining-elements);
if (empty?(minimal-elements))
if (empty?(remaining-elements))
result
else
error("Inconsistent precedence graph ~S.",
remaining-elements)
end if
54 Classes
C H A P T E R 5
else
let choice =
if (empty?(minimal-elements.tail))
minimal-elements.head
else
tie-breaker(minimal-elements, result)
end if;
sort(remove(remaining-constraints,
choice,
test: method (a, b) member?(b, a) end),
remove(remaining-elements, choice),
concatenate(result, list(choice)))
end if
end method sort;
sort(constraints, elements, #())
end method topological-sort;
Slots 5
Slots are the interface to information about instances. They correspond to the
fields or instance variables of other object-oriented programming languages.
By default, each instance of the class has private storage for each slot, so one
instance can have one value in the slot and another instance can have another
Slots 55
C H A P T E R 5
This definition indicates that instances of <point> should have two slots,
horizontal and vertical. The getter method for the first slot is added to
the generic function horizontal, and the getter method for the second slot is
added to the generic function vertical. The setter method for the first slot is
added to the generic function horizontal-setter, while the setter method
for the second slot is added to the generic function vertical-setter.
The following two code fragments are equivalent. Each returns the horizontal
coordinate of a point:
horizontal(a-point)
a-point.horizontal;
The following three code fragments each set the horizontal coordinate of a
point to 10:
horizontal-setter(10, my-point)
horizontal(my-point) := 10;
my-point.horizontal := 10;
* Thisis in contrast to some other languages where slots are accessed through named value ref-
erences.
56 Slots
C H A P T E R 5
Slot Inheritance 5
Slots are inherited from superclasses.
The collection of all the getter and setter generic functions for slots specified in
a class or inherited from its superclasses must not contain any duplicates.
If a superclass is inherited through multiple paths, its slots are inherited once.
For example, if class A has direct superclasses B and C, and both B and C have
D as a direct superclass, A inherits from D both through B and through C, but
the slots defined by D are only counted once. Because of this, multiple
inheritance does not by itself create any duplicates among the getters and
setters.
Note that two classes which specify a slot with the same getter or setter generic
function are disjoint —they can never have a common subclass and no object
can be an instance of both classes.
Slot Specifications 5
A slot specification describes a slot.
A slot specification must include the name of the getter of the slot (i.e. the name
of the generic function to which the getter method will be added). This is how
slots are identified. The specification may optionally include the name of the
setter method. If it does not, a default name is generated by appending
“-setter” to the name of the getter.
A number of other options are available in slot specifications:
■ An initial value for the slot may be specified with an init specification.
■ An init-keyword may be specified. This allows a value for the slot to be
supplied when an instance is created.
■ Slot allocation may be specified. This controls whether storage for the slot is
allocated in each instance, or some other way.
■ A slot may be specifed as constant. There will be no setter for the slot.
■ A type may be specified. The value of the slot will be constrained to be an
instance of that type.
Slots 57
C H A P T E R 5
■ A sealing directive may be specified. See “Define Inert Domain” on page 133
for a complete description of the sealing constraints imposed by this
directive.
For the complete syntax of slot specifications, see the reference entry of
define class on page 366.
The following example defines a class with three slots, using a variety of slot
options.
Init Specifications 5
An init specification provides a default initial value for a slot. It can do this
directly (if it is an init specification of a slot) or it can do it indirectly by
providing a default value for an init-keyword (if it is an init specification of an
init-keyword).
There are three kinds of init specifications:
■ An init value specifies a value that is used to initialize the slot. Each time the
slot needs to be initialized, the identical value is used.
■ An init function specifies a function to be called to generate a value that is
used to initialize the slot. Each time the slot needs to be initialized, the
function is called and its value is used. This allows slots to be initialized to
fresh values, or to values computed from the current program state.
■ An init expression specifies an expression to be executed to generate a value
that is used to initialize the slot. Each time the slot needs to be initialized, the
expression is executed and its value is used. This allows slots to be
initialized to fresh values, or to values computed from the current program
state.
Only one init specification may be supplied in a given slot specification,
inherited slot specification, or initialization argument specification.
In general, an init-function will only be called and an init-expression will only be
executed if its value will actually be used.
58 Slots
C H A P T E R 5
Init Keywords 5
Slot Allocation 5
Constant Slots 5
Slots 59
C H A P T E R 5
Specializing Slots 5
Slots may be specialized by declaring the type of the slot when a class is
created. Specializing a slot has the following effects on the getter and setter
methods of the slot:
■ The automatically defined slot getter method has its single parameter
specialized on the class that specified the slot and has a value type
declaration that indicates that it returns a single value of the type specified
for the slot.
■ The automatically defined slot setter method has its instance argument
specialized on the class that specified the slot, has its new-value argument
specialized on the type specified for the slot, and has a value type
declaration that indicates that it returns a single value of the type specified
for the slot.
The following example demonstrates how an explicitly defined setter method
can be used to coerce a slot value of the wrong type (<sequence>) to the right
type (<simple-object-vector>).
60 Slots
C H A P T E R 5
The assignment expression invokes the method with the new-value parameter
specialized on <sequence>, which reinvokes the function with a new-value
argument that is a <simple-object-vector>, which invokes the slot setter
method.
Using Slots 5
Because slots are accessed through methods in generic functions, they appear
to clients just like any other methods in generic functions. It is possible for a
value to be stored in a slot in instances of one class, but computed from
auxiliary values by instances another class. It is possible to filter the value of a
slot when it is retrieved or stored. In all of these cases, the interface to the
value is a function call, thus hiding the implementation details from clients.
In the following example, the class <view> stores position directly, while
<displaced-view> performs a transformation on the value of the slot when
storing or retrieving it.
Slots 61
C H A P T E R 5
62 Slots
C H A P T E R 5
Overview 5
Instance creation and initialization proceeds through the following steps:
■ The program calls make specifying a class and a set of keyword arguments.
■ Optionally, the default make method may be shadowed by a user-supplied
method specialized with a singleton specializer. This enables the user
method to get at all the arguments to make, and to provide actual
instantiation and initializations based on them. For example, a singleton
method on an abstract class can reinvoke make on a concrete subclass of the
abstract class, passing along the same or augmented initialization arguments.
■ The default make method examines its keyword arguments, which are
known as the supplied initialization arguments. It then produces a set of
defaulted initialization arguments by augmenting the supplied
initialization arguments with any additional initialization arguments for
which default values are defined by the class or any of its superclasses.
If the supplied initialization arguments contains duplicate keywords, make
will use the leftmost occurance. This is consistent with keyword argument
conventions used in function calls.
■ The default make method signals an error if any required init-keyword is
absent from the defaulted initialization arguments, or if any of the defaulted
initialization arguments are not valid for initialization of that class. An
initialization argument is valid if it is specified as an init-keyword in a slot
specification or initialization argument specification, or if it is permitted by
one or more of the initialize methods applicable to an instance of the
class.
■ The default make method allocates an instance and initializes all the slots for
which it can provide values, as follows
make(<dog>)
⇒ {instance of <yorkshire-terrier>}
A program can test to see whether a slot has been initialized, using the
slot-initialized? function, described on page 248. There is no portable
mechanism for resetting a slot to the uninitialized state once it has been
initialized.
To support the slot-initialized? protocol in a virtual slot, programmers
must define a method for slot-initialized? that specializes on the getter
of the slot and the class.
In this example, thet <astronaut> class provides default values for the
favorite-beverage: and name: init-keywords. In addition to indirectly
supplying default values for these slots, this also has the effect of making the
name: argument optional in calls to make on <astronaut>. If the call to
make does not specify a name:, the name: will be added to the defaulted
initialization arguments by the default make method before the defaulted
initialization arguments are checked for completeness.
More than one keyword initializable slot may be initialized from the same
initialization argument (that is, more than one keyword initializable slot may
specify the same init-keyword). However, an error is signaled if a single
define-class form has more than one initialization argument specification
for the same keyword. An error will also be signaled if a single
define-class form has a keyword initializable slot which includes an init
specification and also includes an initialization argument specification for the
same keyword that is either required or provides a default value. These error
situations are all indications of code that can never be reached.
Singletons 5
Singleton types are used to indicate individual objects. When determining
whether a singleton specializer matches a given object, the object must be == to
the object used to create the singleton.
A singleton for an object is created by passing the object to the function
singleton, or by calling the function make on the class <singleton>.
Singleton methods are considered more specific than methods defined on an
object’s class. Singletons are the most specific specializer.
70 Singletons
C H A P T E R 5
Union Types 5
Union types represent the union of the instances of two other types. Union
types are created with the function type-union. They are not classes.
Union types are useful as slot specializers, and describe the return types of
many common functions. For example, the return type of the collection
method on size could be expressed as type-union(<integer>,
singleton(#f)).
red?(kermit)
⇒ #f
The following rules govern subtype? and instance? for union types.
Given
■ x is an object.
■ s1…sm and t1…tn are non-union types.
■ The notation type-union*(t1…tn) stands for any arrangement of nested
calls to type-union, where none of the arguments is a subtype of any
other, and none of the arguments forms an exhaustive partition of any other
type.
Then
type-union(t1, t1) is type equivalent to t1
type-union(t1, t2) is type equivalent to type-union(t2, t1)
type-union(t1, type-union(t2, t3)) is type equivalent to
type-union(type-union(t1, t2), t3)
Union Types 71
C H A P T E R 5
Limited Types 5
Limited types are subtypes of classes constrained by additional criteria.
Limited types are created with the generic gunction limited.
limited(<integer> ,min: 0 max: 255) and limited(<array>,
of: <single-float>) are examples of limited types which are useful both
for error checking and for optimization of compiled code.
Limited types are not classes.
72 Limited Types
C H A P T E R 5
For example:
// accepts integers between -1000 and 1000 inclusive.
define method f (x :: limited(<integer>, min: -1000,
max: 1000))
…
end method f;
//accepts all strictly positive integers.
define method f (x :: limited(<integer>, min: 1))
…
end method f;
Limited Types 73
C H A P T E R 5
74 Limited Types
Figure 6-0
Listing 6-0
C H A P T E R 6 Table 6-0
6 Functions
Contents
Overview 77
Generic Functions 77
Methods 78
Parameter Lists 82
Kinds of Parameters 83
Kinds of Parameter Lists 84
Specializing Required Parameters 86
Keyword Parameters 87
Result Values 89
Parameter List Congruency 91
Parameter Lists of Implicitly Defined Generic Functions 92
Method Dispatch 93
Calling Less Specific Methods 96
Operations on Functions 98
Contents 75
76 Contents
C H A P T E R 6
Functions 6
Overview 6
All operations in Dylan are functions.
Functions accept zero or more arguments, and return zero or more values. The
parameter list of the function describes the number and types of the arguments
which the function accepts, and the number and types of the values it returns.
There are two kinds of function, methods and generic functions. Both are
invoked in the same way. The caller does not need to know whether the
function it is calling is a method or a generic function.
A method is the basic unit of executable code. A method accepts a number of
arguments, creates local bindings for them, executes an implicit body in the
scope of these bindings, and then returns a number of values.
A generic function contains a number of methods. When a generic function is
called, it compares the arguments it received with the parameter lists of the
methods it contains. It selects the most appropriate method, and invokes it on
the arguments. This technique of method dispatch is the basic mechanism of
polymorphism in Dylan.
All Dylan functions are objects, instances of <function>. Generic functions
are instances of <generic-function> and methods are instances of
<method>.
Generic Functions 6
Generic functions can be created with define generic or by calling make on
the class <generic-function>. They are most often created with define
generic.
Generic functions may also be created implicitly by define method or by slot
specifications in class definitions.
A generic function definition includes a parameter list, which constrains the
methods that can be added to the generic function; some aspects of the
parameter must be matched by any method added. In addition, a generic
function parameter list may specify that all keyword arguments are permitted
in a call to the generic function.
Overview 77
Functions
Generic functions created with define generic may be sealed or open. For
details of this option, see “Declaring Characteristics of Generic Functions” on
page 133.
Methods 6
Methods can be created with define method, local, and method program
constituents. define method is used to define a method and add it to a
generic function in a module binding. local is used to create local bindings
that contain self-recursive and mutually-recursive methods. method is used to
create and return methods for immediate application, for use as function
arguments, or for storage in a variable or other data structure. Methods are
also created for slot getters and setters when a class is created.
Methods cannot be created with make.
The parameters and return values of a method are described in its parameter
list. The specializers in the parameter list declare the types of the arguments
acceptable to the method. The method can be called only with arguments that
match the specializers of the parameters. A complete description of parameter
lists is given in “Parameter Lists” on page 82.
When the method is invoked, it executes its implicit body. Statements in the
implicit body are executed in order, in an environment which contains the
parameters bound to the arguments.
78 Overview
C H A P T E R 6
Functions
Local Methods 6
Overview 79
C H A P T E R 6
Functions
Bare Methods 6
Methods can also be created and used directly with the method statement.
Methods created directly can be stored in module variables, passed as
arguments to generic functions, stored in data structures, or immediately
invoked.
The following example creates a method and stores it in the module variable
square. It is appropriate to define a method in this way (rather than with
define method) when the protocol of the function being defined does not
require multiple methods.
80 Overview
C H A P T E R 6
Functions
Methods created directly with the method statement may be called directly or
they may be added to generic functions. Usually, however, when you want to
add a method to a generic function, you create and add the method in a single
declarative step, with define method.
Closures 6
score-david(0)
⇒ 100
score-david(10)
⇒ 110
score-david(10)
⇒ 120
score-diane(10)
Overview 81
C H A P T E R 6
Functions
⇒ 410
score-david(0)
⇒ 120
score-david(0)
⇒ 120
double-david(10)
⇒ 140
score-david(0)
⇒ 140
Parameter Lists 6
The parameter list of a function describes the number and types of the
arguments which the function accepts, and the number and types of the values
it returns.
82 Parameter Lists
C H A P T E R 6
Functions
The parameter list of a generic function is used to define the overall protocol of
the generic function. It constrains the methods that may be added to the
generic function, through the parameter list congruency rules described on
page 91. It may also specify that calls to the generic function may contain any
keyword arguments.
The parameter list of a method specifies the types of arguments to which the
method is applicable, and declares local bindings to which those arguments
will be bound during the execution of the body of the method. It may also
declare the return value types of the method.
Kinds of Parameters 6
Dylan parameter lists support required parameters, rest parameters, keyword
parameters, and sometimes a next-method parameter. They also may include
return type declarations.
The complete syntax of parameter lists is given in “Methods” on page 412.
Required parameters correspond to arguments which must be supplied when a
function is called. The arguments are supplied in a fixed order and must
appear before any other arguments.
Each required parameter may be a name or a name specialized by a type.
Specifying a type declares that supplied argument must be a general instance
of that type.
A rest parameter allows a function to accept an unlimited number of
arguments.* After the required arguments of a function have been supplied,
any additional arguments are collected in a sequence, which is passed as the
value of the rest parameter. This sequence may be immutable, and it may or
may not be freshly allocated. The types of rest parameters cannot be declared.
Keyword parameters correspond to arguments that are optional and may be
given in any order. Symbols are used among the arguments to guide matching
of arguments to parameters. These symbols are usually written in keyword
syntax and so they are known as keywords. Keyword arguments can only be
supplied after all required arguments are supplied. Keyword parameters may
be specialized, restricting which values may be supplied for them. Keyword
* In
practice, an implementation may place a reasonable limit on the number of arguments that
may be passed to any function.
Parameter Lists 83
C H A P T E R 6
Functions
parameters may also be given default values to be used when the caller does
not supply a value.
Required parameters come first in the parameter list, followed by the rest
parameter, if any, and then the keyword parameters, if any. A rest parameter is
indicated by the token #rest followed by the name of the parameter.
Keyword parameters are indicated by the token #key followed by the keyword
parameter specifiers, optionally followed by the token #all-keys.
If #rest and #key are used in the same parameter list, #rest must come
first. The rest parameter will be bound to a sequence containing all the
keyword arguments and their corresponding values.
A next-method parameter is indicated by the token #next, followed by the
name of the parameter. It is not normally necessary to specify a next-method
parameter explicitly. If a next-method parameter is not specified by the
programmer, define method inserts one with the name next-method. If an
explicit next-method parameter is given, it must come after the required
parameters and before the rest and keyword parameters. Details of using
next-method are given in “Calling Less Specific Methods” on page 96.
84 Parameter Lists
C H A P T E R 6
Functions
Parameter Lists 85
C H A P T E R 6
Functions
A call to a function may supply the same keyword argument more than once.
When this is done, the leftmost keyword/value pair is used.
86 Parameter Lists
C H A P T E R 6
Functions
Keyword Parameters 6
The syntax of a keyword parameter is:
If keyword is not supplied, then name is used to indicate both the keyword and
the name of the parameter. If the keyword and name are given independently,
the keyword is used when calling the method, and the name is used as the name
of the parameter inside the body of the method.
The expression supplies a default value for the parameter. It is used when the
method is called and the keyword is not supplied. It is executed each time the
method is called and the corresponding keyword argument is not supplied. If
no expression is specified, the parameter corresponding to an unsupplied
keyword argument is initialized to #f. The expression is executed in a scope
that includes all the preceding parameters, including required parameters, the
rest parameter (if any), the preceding keyword parameters, and the
next-method parameter (if any).
In the following example, all three keyword parameters have default values,
and all three use the same name for the keyword and the parameter.
The caller can choose which keyword arguments to supply and what order to
supply them in:
percolate (brand: #"java", cups: 10);
percolate (strength: #"strong",
brand: #"starbucks",
cups: 1);
Parameter Lists 87
C H A P T E R 6
Functions
The following method has two keyword parameters. In each, the name of the
keyword and the name of the parameter is specified separately. The first
keyword parameter has a default value, the second does not.
The keyword parameter syntax in which the keyword name and parameter
name are given separately is needed to allow keyword names such as
position: without forcing the method to use position as a local binding.
If a method uses position as a local binding, it cannot access the module
binding position (which contains a function). The local binding would
shadow the module binding.
All required arguments must be supplied before any keyword arguments can
be supplied. The following call to layout will signal an error:
layout(position: 100, size: 500);
88 Parameter Lists
C H A P T E R 6
Functions
method (#key X)
let X :: <integer> = X;
... X ...
end method;
If a keyword parameter is given a type, if #f is not an instance of that type, and
if they keyword parameter is not given a default value, then the keyword
parameter is essentially required. An error of type <type-error> will be
signaled if a call to the method does not include the keyword.
The following examples include keyword parameters that include both a type
and a default value.
Result Values 6
Parameter lists may include value declarations. Value declarations come at the
end of the parameter list and are separated from the parameters by =>. For
each return value, a value declaration can specify a name and an operand or
just a name if the type is <object>. The complete syntax of value declarations
is given in “Methods” on page 412.
The result of executing the operand at the time the function is defined is a type,
called a value type. The name never comes into scope. It is included for
documentation and for syntactic consistency with parameters. It is valid for
the same name to be used in both one parameter and one value declaration in
the same parameter list; this is useful as documentation that a function returns
one of its arguments.
The last value declaration can be preceded by #rest to indicate a variable
number of return values. A value declaration preceded by #rest is called a
rest value declaration. A value declaration not preceded by #rest is called a
required value declaration. The value type in a rest value declaration is the
Parameter Lists 89
C H A P T E R 6
Functions
type of each one of the remaining individual values, not the type of a
conceptual sequence of multiple values.
If a parameter-list does not contain a value declaration, it defaults to =>
#rest x :: <object>. That is, the function can return any number of
values of any type.
A function will always return the number and types of values declared in its
parameter-list. More precisely:
■ Each value returned by a function must be an instance of the corresponding
value type, or else an error of type <type-error> will be signaled.
■ If fewer values are returned by the function’s body (or by the applicable
method if the function is a generic function) than the number of required
value declarations in the function’s parameter-list, the missing values are
defaulted to #f and returned. If #f is not an instance of the corresponding
value type, an error of type <type-error> is signaled.
■ If a function does not have a rest value declaration, and more values are
returned by the function’s body (or by the applicable method if the function
is a generic function) than the number of required value declarations in the
function’s parameter-list, the extra values are discarded and not returned.
Because of the parameter list congruency rules for result value declarations, the
values returned by a generic function do not have to be checked by the generic
function. The check inside a method will always be enough to verify that the
return values are valid for the generic function.
90 Parameter Lists
C H A P T E R 6
Functions
Note that the following example does not declare a return value of type
<number>. It declares a return value of type <object>. To specify a type, both
the name and the type must be specified. If only one is given, it is taken as the
name.
Parameter Lists 91
C H A P T E R 6
Functions
92 Parameter Lists
C H A P T E R 6
Functions
using define method and slot getter and setter methods defined using
define class.
■ The implicitly defined generic function has the same basic argument pattern
as the methods. Either they must all require a fixed number of arguments,
they must all accept a variable number of arguments, or they must all accept
keyword arguments. A set of methods that includes members with more
than one of these patterns violates the parameter list congruency
requirement, and is an error.
■ The implicitly defined generic function has the same number of required
arguments as the methods. A set of methods that includes members with
different numbers of required arguments violates the parameter list
congruency requirement, and is an error.
■ Each required argument of the implicitly defined generic function is
specialized on <object>.
■ If the implicitly defined generic function accepts keyword arguments, it does
not have any mandatory keywords, nor does it accept all keyword
arguments.
■ The implicitly defined generic function has a rest value declaration of
<object>.
Method Dispatch 6
When a generic function is called, the generic function uses the types of the
arguments to determine which methods to call. This process is called method
dispatch.
Method dispatch occurs in three phases. First, all the applicable methods are
selected. Next, the applicable methods are sorted by specificity. Finally, the
most specific method is called.
Method Specificity 6
For any two methods A and B that are applicable to a given generic function
call, one method may be more specific than the other, or the methods may be
ambiguous methods.
Method Dispatch 93
C H A P T E R 6
Functions
94 Method Dispatch
C H A P T E R 6
Functions
#(<vulcan>,<intelligent>,<sentient>,<humanoid>,<bipedal>,<life-fo
rm>)
The class precedence lists computed for two different classes may have
different precedence orders for some intermediate superclasses. This is not a
problem as long as there is no class which inherits from both classes. For
example, we could define a class <human> as follows:
For the class <human> defined as above, the class precedence list would be
(<human>,<humanoid>,<bipedal>,<intelligent>,<sentient>,<life-form
>)
It is not a problem that the two class precedence lists give different orders to
some of the intermediate superclasses such as <bipedal> and <sentient>
as long as no class is added which inherits from both <vulcan> and <human>.
When sorting the applicable methods, each specializer needs to be viewed with
respect to the class precedence list for the class of the argument passed to the
generic function in that argument position. For example, given the following
definitions
Method Dispatch 95
C H A P T E R 6
Functions
96 Method Dispatch
C H A P T E R 6
Functions
In the usual case, next-method is called with no arguments. This indicates that
the next-method should be passed the same arguments that were supplied to
the current method.
It is valid to supply arguments, including different arguments, when calling
next-method. However, if you pass different arguments, the new arguments
must result in the same ordered sequence of applicable methods as the original
arguments. Otherwise, the program behavior is undefined.
In some cases, the methods in a generic function accept different keyword
arguments. In such cases, it’s convenient for the methods also to accept a rest
parameter. That way, all the keyword/value pairs passed to the generic
function are captured in the rest parameter. By using apply, the next-method
can be invoked with the complete set of arguments. (This technique is only
necessary, of course, when the method calls next-method and passes arguments
explicitly.)
As usual, if there are duplicates of a given keyword argument, the leftmost
occurance is used. This allows keyword arguments to be easily overridden.
Method Dispatch 97
C H A P T E R 6
Functions
Operations on Functions 6
The Dylan language defines a number of functions which operate on other
functions.
There are two broad categories of these functions:
■ Introspective functions take a function as an argument and return
information about it. These are described in “Reflective Operations on
Functions” on page 340.
■ Higher order functions take one or more functions as arguments, and return
a new function. These are described in “Functional Operations” on page 334.
98 Operations on Functions
Figure 7-0
Listing 7-0
C H A P T E R 7 Table 7-0
7 Conditions
Contents
Background 101
Overview 103
Signalers, Conditions, and Handlers 103
Exception Handling 105
Stack Model 105
Recovery and Exits 106
Restarts 109
Recovery Protocols 110
Condition Messages 111
Introspective Operations 112
Contents 99
100 Contents
C H A P T E R 7
Conditions 7
Background 7
A long-standing problem of software engineering is the need to develop an
organized way to deal with exceptions, situations that must be handled
gracefully but that are not conceptually part of the normal operation of the
program.
Of course it is possible to program exception handling without using special
linguistic features. For example, all functions could return an extra result that
indicates whether they succeeded or failed, functions could take an extra
argument that they consult if an exception occurs, or a designated
exception-handling function could be called whenever a problem arises. All of
these approaches have been used in one real-life system or another, but they
are deficient in two ways. First, they are too informal and don’t provide
enough structure to allow an organized, systematic approach to exception
handling. Second, and more importantly, the first two approaches do not
provide textual separation between “normal code” and “code for dealing with
exceptions”; exception-related code is sprinkled throughout the program. This
leads to two problems: one is the well-known mistake of forgetting to test error
codes and thus failing to detect an exception (perhaps because the programmer
believed the error could never occur); the other is that program clarity is lost
because it isn’t easy to think about the main flow of the program while
temporarily ignoring exceptions.
All exception systems involve the concept of “signal” (sometimes with a
different name, such as “raise” or “throw”) and the concept of “handle”
(sometimes with a different name such as “on-unit” or “catch”). Most
exception systems dynamically match signalers with handlers, first invoking
the most recently established matching handler still active, and then, if that
matching handler declines to handle the exception, invoking the next most
recent matching handler, and so on.
In addition, it is necessary to have a way to clean up when execution of a
function is terminated by a non-local exit initiated either by the function itself
or by something it explicitly or implicitly called.
Exception systems may be name-based or object-based, they may be exiting or
calling, and they may or may not provide formal recovery mechanisms.
Background 101
Conditions
102 Background
C H A P T E R 7
Conditions
Overview 7
The Dylan exception system is built on top of an underlying signal system.
Together, the signal system and the exception system comprise the Dylan
condition system.
At the signal layer, the condition system provides a way of establishing a
run-time connection between a signaler and a handler through a condition.
This is essentially a run-time analog to the more usual fixed connection
between a caller and a callee established through function-name matching.
This layer of the condition system is little more than a way to locate and call a
function. The function call does not necessarily involve any exceptional
situation or non-local flow of control.
At the exception layer, the condition system specifies a set of protocols for
categorizing and handling exceptional situations through recovery or exit.
This higher layer provides overall structure, eliminates the possibility of failing
to notice an exceptional situation, and provides a clean separation between
“normal code” and “code for dealing with exceptions.”
The non-local exit and clean-up features of the block statement are often used
in conjunction with the facilities described in this chapter. block is described
on page 392.
Overview 103
C H A P T E R 7
Conditions
Conditions
Exception Handling 7
A set of classes, functions, and associated conventions extend the underlying
condition handling capabilities to provide a complete exception handling
facility.
The classes are described in “Conditions” on page 234, and the functions are
described in “Signaling Conditions” on page 346.
Stack Model 7
Condition handlers are installed dynamically, with more recent handlers
shadowing previously installed handlers. In addition, exception handling
often involves the use of non-local exits. For these reasons it is useful to
describe the behavior of the exception system using the following terms from
the stack model of function calling.
■ outside stack
The state existing just before the handler was established
■ signaling unit
The conceptual program component that includes the expression that
signaled the condition and does not include the expression that established
the handler. This informal concept provides a notion of where the interface
boundary between the signaler and the handler lies.
■ middle stack
The state existing just before the signaling unit was called, minus the outside
stack. In other words, the state between the handler and the signaling unit.
■ inside stack
The state existing just before signaling occurred, minus the middle stack and
outside stack. In other words, the portion of the signaling unit prior to the
call to signal.
Conditions
Figure 7-1
return
call
non-local exit
inside stack signalling unit
return
signal(…)
handler executes here
The handler in Figure 7-1 may either return normally, in which case execution
resumes as the call to signal returns normally, or the handler may make a
non-local exit, such as calling the exit function from a dynamically active
block statement.
Conditions
The simplest way to handle an exception is to exit the signaling unit by taking
a non-local exit to a target established in the outside stack. The exception
clause of the block statement provides a convenient mechanism for
accomplishing this.
A less common handling style is to exit the signaling unit by taking a non-local
exit to a target established in the middle stack, thus leaving the handler in force.
Instead of exiting, a handler can recover by returning control to the signaling
unit. This can be done either by returning values that the signaling unit will
understand or by taking a non-local exit to a target established in the inside
stack.
The following examples show three ways of handling a copy-protection
violation while copying a series of files. Note that the signaling code does not
need to know how the condition will be handled. The only changes are in the
code which handles the condition.
Conditions
Conditions
Restarts 7
Recovering or exiting can be accomplished directly, or a more formal
mechanism called restarting can be used. Using restarts provides more
assurance that the handler and the signaling unit agree on the meaning of what
they are doing and provides some isolation of the handler from names and
data representations internal to the signaling unit.
A handler restarts by signaling a restart. All restarts are instances of
<restart>. Any values needed for recovery are passed in the restart (that is,
in initialization arguments that the restart remembers, typically in slots). The
restart is handled by a restart handler which either returns or takes a non-local
exit. If the restart handler returns some values, signal returns those values
and the handler that called signal also returns them. The call to signal
from the signaling unit that signaled the original condition returns the same
values, and the signaling unit recovers as directed by those values.
Conditions
Recovery Protocols 7
For every condition class there should be a recovery protocol that defines the
meaning of handling by returning, the meaning of the values returned, and
which restart handlers are supposed to be established by the signaling unit.
The recovery protocol tells the handler what to expect from the signaler. For
many condition classes, this is the empty protocol: handling by returning isn’t
allowed, and no particular restart handlers are provided. In this case only
handling by exiting is possible. (Exiting might be accomplished by signaling a
restart whose handler was established in the outside or middle stack and does
a non-local exit back to where it was established, or by an ordinary non-local
exit.) The recovery protocol for a subclass should be compatible with the
recovery protocol of a superclass. That is, a handler that applies a class’s
recovery protocol should operate correctly when the condition is an instance of
some subclass of that class.
An example recovery protocol for a hypothetical <unbound-slot> condition
could include the following:
■ Returning is allowed. Returning a value uses that value as if it had been the
contents of the slot.
■ A restart handler for <new-value> is available. <new-value> has
initialization arguments value:, the value to use, and permanent:, which
indicates whether to store the value into the slot or leave the slot unbound.
At present, no formal mechanism is provided for describing recovery protocols;
they are left to the documentation of a condition class. Introspective functions
are provided for discovering which recovery facilities are actually available,
but this is different from (and sometimes is a superset of) the recovery facilities
guaranteed by a recovery protocol always to be available.
The debugger is the condition handler of last resort which receives control if no
program-provided handler handles a serious condition. (This is true even if
the debugger provided cannot analyze or intervene in the execution of
programs but can only abort or restart them. The debugger might be merely a
“core dumper,” a “bomb box,” or something similar.) An interactive debugger
ought to offer the user the ability to signal any restart for which a restart
handler is applicable and to return if the condition’s recovery protocol allows
it. This could, for example, be done with a menu titled “Recovery.”
Conditions
Condition Messages 7
Some condition classes provide a message to communicate the meaning of the
condition to the program user.
Condition messages are constructed using format strings. A format string is a
string template into which values can be inserted to construct a message. The
two-character format directives %d, %b, %o, %x, %c, %s, and %= are replaced by
the corresponding element of the associated sequence of format arguments.
Upper and lower case letters are equivalent in these format directives. The
inserted value is formatted according to the following table:*
The text printed by the %= format directive for any given object is
implementation-defined. The behavior when a format argument is not of the
type specified in the table above is implementation-defined. The behavior
*
These format directives are designed for compatibility with C’s printf, with some
ommisions and with the addition of %=.
Conditions
Introspective Operations 7
The function do-handlers allows introspection of all the dynamically active
handlers. For each handler, it provides the type, test, function, and
init-arguments that were declared when the handler was installed.
do-handlers is typically used by the debugger or other error-recovery
system to discover what restart handlers are available before signaling a restart.
Additional operations support introspection on conditions. See “Introspection
on Conditions” on page 351 for a complete description of these introspective
functions.
8 Collections
Contents
Overview 115
The Iteration Protocol 115
Collection Keys 116
Iteration Stability and Natural Order 116
Mutability 117
Collection Alteration and Allocation 117
Collection Alignment 118
Defining a New Collection Class 119
Tables 120
Element Types 122
Limited Collection Types 124
Creating Limited Collection Types 127
Contents 113
114 Contents
C H A P T E R 8
Collections 8
Overview 8
Collections are aggregate data structures which map from keys to elements.
All collections are instances of the class <collection>.
<collection> has two covering subclasses: <sequence> and
<explicit-key-collection>. Every concrete subclass of <collection>
must also be a subclass of <sequence> or <explicit-key-collection>.
Sequences use successive non-negative integers as keys; explicit key
collections may use any object as a key. Both of these classes have predefined
subclasses and may be additionally subclassed by programmers. See
“Collections” on page 199 for a complete description of these classes.
A large number of functions are available on collections, including functions
for iteration, mapping, random access of elements, sorting, filtering, etc. See
“Collection Operations” on page 281 for a complete description of these
functions.
Overview 115
Collections
With notable exceptions, two or more iterations over the same collection are not
guaranteed to produce the same values in the same order, even if the collection
is unaltered. For details, see “Iteration Stability and Natural Order” on
page 116.
The built-in collection functions are implemented in terms of the iteration
protocol. When defining a new collection class, a programmer need only
define the iteration protocol for the class. Once this is done, instances of the
class can be used with all the built-in collection functions. Of course, in some
cases it will be more efficient to define methods on these functions optimized
for the new class, rather than relying on the default implementation based on
the iteration protocol.
Collection Keys 8
All collections in Dylan are keyed. That is, all collections can be viewed
abstractly as partial functions that map keys to elements. (This choice
precludes pure sets from being considered collections, although it is
straightforward simply to ignore the keys for a collection and consider it
simply as a set of elements.) The element function implements this partial
mapping of keys to elements.
Every collection has a key test, which is the test used for determining whether
a given key matches a key in the collection. The key test of a collection can be
accessed using the key-test function.
Collections
The order in which elements and keys are enumerated by the iteration protocol
for a particular iteration is known as the natural order for that iteration over
the collection. If a collection is stable under iteration, then every iteration over
that collection will have the same natural order, and we may speak of the
natural order of the collection itself. Most of the operations on collections are
required to operate in natural order, usually for the purpose of understanding
interactions among side effects.
Mutability 8
Some collections can be modified after they have been created while others
cannot. The <mutable-collection> and <stretchy-collection>
mixin classes are provided to allow methods to distinguish between mutable
and immutable collections. Instances of <mutable-collection> can have
their elements changed after they are created. Instances of
<stretchy-collection> can have keys added and removed after they are
created.
An element of a mutable collection is set to a new value with
element-setter. If the collection is not stretchy, than the key specified must
already be present in the collection; its value will be changed. If the collection
is stretchy, then the key will be added if it is not already present. If the
collection is a stretchy sequence and the key is not already present, then the
size of the sequence will first be set to the new key minus 1, and then the value
of the new key will be set.
A key and its corresponding value can be removed from an explicit key
collection with the function remove-key!.
Mutability 117
C H A P T E R 8
Collections
■ The ordering of the key/value pairs changes. This type of alteration is only
possible for explicit key collections which are stable under iteration.
A function destructively modifies its argument collection if calling the function
could alter the contents of the argument collection. Unless explicitly
documented to do so, functions do not destructively modify their arguments.
The ! convention, described on page 23, is used to indicate some destructive
operations.
Unless explicity noted, destructive operations are not required to leave their
arguments in a well-defined state. More particularly, a destructive operation
does not in general turn the argument into the result. It may reuse components
of the argument or alter the argument in some unpredictable way in order to
produce the result. As a general rule, the return value of the function should be
used.
A collection C is fresh if modification of any pre-existing collection's contents
can never modify the contents of C and if modifications to C can never modify
the contents of any pre-existing collection. Immutable collections cannot be
modified, so a fresh immutable collection can share structure with other
immutable collections.
For example, given that <pair> is mutable and the result of a call to list is a
fresh instance of <pair>, we can guarantee that the following expression is
always false:
list(1) == list(1)
Collection Alignment 8
Some operations on collections are defined to allow the use of more than a
single collection. For example, some looping functions accept any number of
collections and operate on these collections in parallel. Each pass through the
loop uses one element from each collection. The presence of collections which
are unstable under iteration can create problems for multi-collection operations
unless special care is taken. If iteration is effectively performed in random
order, then naively performing parallel iterations over two different collections
would randomly combine values from the two collections. This would
presumably have no meaning.
Collections
Collections
Tables 8
Tables map arbitrary keys to elements. Table keys may be any object, including
complex objects such as strings. All tables are instances of <table>. <table>
is the only instantiable subclass of <explicit-key-collection> defined
by Dylan. Tables are unstable under iteration.
The iteration protocol for tables is implemented in terms of the function
table-protocol. Every concrete subclass of <table> must provide or
inherit a method for table-protocol. This function accepts a table as an
argument, and returns an equivalence predicate and hash-function, as
described below.
The equivalence predicate of a table is used to compare keys. (It is the table’s
key-test.) The table maps keys that are equivalent under the predicate to the
same table element. An equivalence predicate is a boolean function of two
arguments that returns true if and only if the arguments are considered to be
the same according to some specified criteria. For a function to be used as an
equivalence predicate, it must be reflexive, commutative, and transitive. That
is, for a function F and any arguments X, Y, and Z in the domain of F, the
following must be true:
■ F(X,X) must be true.
■ F(X,Y) must be true if and only if F(Y,X) is true.
■ If both F(X,Y) and F(Y,Z) are true then F(X,Z) must be true.
An equivalence class (for an equivalence predicate) is a set of objects, or
potential objects, that are all the same under the specified equivalence
120 Tables
C H A P T E R 8
Collections
predicate and different from all objects not in the class. (This use of the term
“class” does not refer to Dylan classes.)
An object is said to be visibly modified with respect to an equivalence
predicate if the modification changes the equivalence class of the object. The
modifications that are visible to an equivalence predicate are determined by the
definition of the predicate. (For example, changing a character in a string
would be a visible modification with respect to an equivalence predicate that
compared strings character by character, but it would not be a visible
modification with respect to an equivalence predicate that compared objects by
identity, without regard for their contents.)
If an object X is a key in a table T and is visibly modified with regard to the test
function of T, then the consequences are unspecified if any of the following
objects are used as a key in any subsequent operations on T:
■ The original object, X.
■ Some object Y that is in the same equivalence class (as determined by the
test function) as X prior to the modification of X.
■ Some object Z that is in the same equivalence class (as determined by the
test function) as X after the modification of X.
Each table also has an associated hash function, which is a function that relates
table keys and table elements by computing hash codes. A hash code is a
conceptual object consisting of a hash id and its associated hash state. (It is not
an actual Dylan object.) A hash id is an integer encoding of an object. A hash
state is an object of implementation-dependent type which is associated with a
particular hash id and can be used by the implementation to determine
whether the hash id has been invalidated. A hash function accepts one
argument, a key, and returns two values, a hash id and a hash state, which
together represent the hash code.
Each hash function is associated with a specific equivalence predicate, and
must obey the following constraints:
■ The domain of the hash function must include the domain of valid
arguments to the corresponding equivalence predicate. A hash function
need not be defined for all Dylan objects, only those which are acceptable as
arguments to the equivalence predicate.
■ All objects in a given equivalence class have the same (=) valid hash id,
where validity is determined from the associated hash state.
Tables 121
C H A P T E R 8
Collections
In addition, a hash function should have the property that the hash ids
computed by it are well distributed over the range of possible values. That is,
it should be unlikely that two randomly chosen equivalence classes have the
same valid hash id.
Element Types 8
Each instance X of <collection> has a conceptual element type which is an
instance of <type>. If the element type of X is T, X stores elements of type T.
The element method will always return an instance of T and the
element-setter method (if X is mutable) will accept any instance of T. The
analogous functions returned by the iteration protocol also return/accept any
instance of T.
Each subclass C of <collection> has a conceptual element type which is
either T1 or indefinite ⇐ T1, where T1 is a type. (The symbol “⇐ “ in the
“indefinite ⇐ T1” notation is an abbreviation for “subtype.”)
If the element type of C is T1, each general instance of C must have an element
type T2 that is type equivalent to T1. Each subclass of C must have an element
type T3 that is type equivalent to T1.
If the element type of C is indefinite ⇐ T1, each general instance of C must have
an element type T2 that is a subtype of T1. Therefore element on that instance
will return an instance of T1 (and will not return all possible instances of T1 if
T2 is a proper subtype of T1). It is not determined by C what the applicable
element-setter method will accept (thus C's element type is said to be
"indefinite"). Each subclass of C must have element type T3 or indefinite ⇐ T3,
where T3 is a subtype of T1.
User-defined collection classes must also follow these rules.
Collections
Note: the above statements about the value returned by element only apply
when no default: keyword argument is specified.
Collections
Note: K1 and K2 are subtypes of <character> that have not been given
standardized names.
By convention, if C is an instantiable subtype of <collection> and C's
element-type is indefinite ⇐ <object>, then instantiating C produces a
collection whose element type is <object>.
Instantiating <range> produces a collection whose element-type is
unspecified except that it is a subtype of <real> and every element of the
range is an instance of the element type.
The preceding section describes the element type of every object that is created
by make of an instantiable built-in collection class. The element type of an
instance of a user-defined collection class is unspecified, but should follow the
rules given here in order to preserve the property that any operation that
works on an instance of a supertype must work on an instance of a subtype.
Collections
each instance is size(D) and the dimensions of each instance are the elements
of D. You cannot specify both size: and dimensions: in the same type.
Some limited collection types are instantiable. make(limited(C, …), …)
returns a direct instance of some subclass of C. Typically this class is not
standardized and its name is not exported, but it is valid for this class to be C
itself. There is nothing special about this class; it is simply a class known to the
applicable limited method and its creation is subject to all the usual sealing
restrictions.
An object X is an instance of a limited collection type limited(C, of: T2,
size: S) if and only if all of the following are true:
■ object-class(X) is a subclass of C.
■ X's size matches S, as described above.
■ If X is an instance of <stretchy-collection> then S must be #f.
■ The element type of X is equivalent to T2.
An object X is an instance of a type limited(C, of: T2, dimensions:
D) if and only if all of the following are true:
■ object-class(X) is a subclass of C.
■ dimensions(X) = D.
■ X is not an instance of <stretchy-collection>.
■ The element type of X is equivalent to T2.
Each element of an instance of a limited collection type must be an instance of
the element type. Fetching an element of the collection is guaranteed to return
an instance of the element type. Setting or initializing an element will check
that the new element is an instance of the element type and signal an error of
type <type-error> if it is not.
If L1 is a subtype of L2 and L2 is a limited collection type, then L1 is either a
singleton of an instance of L2 or a limited collection type that satisfies one of the
following sets of rules:
1. If neither L1 nor L2 specifies a dimensions: attribute, let L1 be
limited(C1, of: T1, size: S1), and L2 be limited(C2, of: T2,
size: S2). All of the following must be true:
n C1 is a subclass of C2.
n If S2 is not # f, S1 = S2.
Collections
Collections
Methods on limited support the creation of instantiable limited types for the
following classes:
■ <table>
■ <object-table>
Collections
■ <array>
■ <vector>
■ <simple-vector>
■ <stretchy-vector>
■ <string>
■ <range>
These methods are are described in Chapter 12, “The Built-In Functions,” on
page 251.
9 Sealing
Contents
Overview 131
Explicitly Known Objects 131
Declaring Characteristics of Classes 132
Declaring Characteristics of Generic Functions 133
Define Inert Domain 133
Rationale 134
Pseudosubtype Examples 136
Abbreviations for Define Inert Domain 136
Implied Restrictions on Method Definitions 137
Contents 129
130 Contents
C H A P T E R 9
Sealing 9
Overview 9
This chapter describes techniques for sealing portions of a Dylan program by
declaring that classes or functions will never be used in particular ways, or will
never be extended in particular ways. These sealing directives enable a range
of compiler optimizations, and also clarify the programmer’s intent.
The sealing directives include:
■ Declaring a class to be sealed or open. This controls whether a class can
be directly subclassed outside the library in which it is defined.
■ Declaring a class to be abstract or concrete. This controls whether a
class can have direct instances.
■ Declaring a class to be primary or free. This controls how a class can be
used for multiple inheritance.
■ Declaring a generic function to be sealed or open. This controls whether
methods can be added to the generic function from outside the library in
which the generic function is defined.
■ Using define inert domain, or using the abbreviations define
inert method and inert slot. These disallow the addition of some
methods from outside the library in which the generic function is defined.
With the exception of define inert domain, these directives are expressed
as adjectives on the generic function definition, class definition, method
definition, or slot specification.
Overview 131
Sealing
Sealing
Sealing
The definition of class <c> would be valid if it appeared in the same library as
the preceding definitions or in a library used by them, but invalid if it appeared
in a different library. The reason is that without the definition of <c>, the
method defined on m is not within the domain declared by the define
inert domain, but with the definition of <c> the method is within that
domain.
Rationale 9
define inert domain permits the compiler to assume certain properties of
the program which can be computed based on explicitly known classes and
methods, with a guarantee that an attempt to violate any of those assumptions
will be detected.
Sealing
The goal of rule 3 is that the creation of the class C must not make any method
M applicable to a part of the inert domain to which it was not previously
applicable.
The “potentially blocks” concept describes the mechanism for testing whether
the set of objects that are instances of both Si and Ti (i.e. to which the method is
applicable at the ith argument position and that are within the inert domain at
that argument position) would change as a result of creating C. By specifying
what valid programs are allowed to do, rule 3 implicitly specifies the
assumptions a compiler can make. A define inert domain definition
accomplishes this by permitting the compiler to eliminate some of the known
methods on a generic function from the set of methods that might be applicable
to a particular call at runtime. For example, if this leaves exactly one applicable
method, the compiler can eliminate a run-time method dispatch and consider
additional optimizations such as inlining.
Specifically, suppose the compiler is compiling a call to G and has determined
that the argument at position i is an instance of some type U (where U is not
necessarily a standard Dylan type, but could instead be a compiler-internal
extension to the type system, such as a difference of two types). For the
compiler to be able to rely on the define inert domain definition, U must
be a subtype of Ti. For the compiler to determine that M is not applicable, U
must be disjoint with Si. Creating C can't change whether U is a subtype of Ti,
but it can change whether U is disjoint with Si. If there could be an object that
is simultaneously an instance of U, C, and Si, it would violate the compiler's
assumption that M is not applicable in the call to G, and therefore creating C
would be a sealing violation. If there can't be such an object, then creating C is
allowed.
This maps onto rule 3 as follows (ignoring for the moment the added
complication of limited types that lead to the use of the pseudosubtype
relationship rather than subtype):
U is a subtype of Dk and therefore is a subtype of Ti, because subtype is
transitive.
Dk is not a subtype of Si, because if it were then U could not be disjoint from Si.
Dj is a subtype of Si.
If U and C would have a non-empty intersection, then the creation of C must be
prevented, else U would no longer be disjoint from Si. One possible U is the set
of all general instances of Dk that are not also general instances of any of the
explicitly known direct subclasses of Dk. That U would indeed have a
Sealing
Pseudosubtype Examples 9
Suppose A and B are disjoint subclasses of <collection>, Si is limited(A,
of: T), and Ti is limited(B, of: T). Thus, Si and Ti are disjoint and M is
outside the inert domain. If C inherits from A and B it should be potentially
blocked by M, because an instance of limited(C, of: T) would be an
instance of both Si and Ti. Since B is not a subtype of Ti, there would be no
blockage if the constraints in rule 3 were defined in terms of subtype.
However, B is a pseudosubtype of Ti, so specifying rule 3 using the
pseudosubtype relationship correctly causes M to potentially block C.
Suppose Si is limited(<stretchy-vector>, of: <integer>) and Ti is
limited(<sequence>, of: <integer>). Attempt to create
<stretchy-string>, a direct subclass of <stretchy-vector> and
<string>. The element-type of <stretchy-string> must be a subtype of
<character>, therefore, assuming <integer> and <character> are
disjoint, <stretchy-string> is disjoint from both Si and Ti, and so is not
blocked. This example shows the need for the non-disjointness requirement in
the definition of pseudosubtype.
Sealing
The inert slot option to define class defines a slot and also makes the
getter generic function inert over the class, and the setter generic function, if
there is one, inert over the type of the slot and the class.
The following two program fragments are equivalent:
and
Sealing
10 Macros
Contents
Overview 141
Compilation and Macro Processing 141
Extensible Grammar 144
Definition Macros 144
Statement Macros 145
Function Macros 145
Macro Names 146
Rewrite Rules 147
Patterns 148
Special Rules for Definitions 153
Special Rules for Statements 153
Special Rules for Function Macros 154
Pattern Variable Constraints 154
Intermediate Words 156
Templates 156
Auxiliary Rule Sets 158
Hygiene 159
Intentional Hygiene Violation 160
Hygiene Versus Module Encapsulation 160
Rewrite Rule Examples 161
Statement Macros 161
Definition Macros 170
Additional Examples 173
Contents 139
140 Contents
C H A P T E R 1 0
Macros 10
Overview 10
A macro is an extension to the core language that can be defined by the user, by
the implementation, or as part of the Dylan language specification. Much of
the grammatical structure of Dylan is built with macros. A macro defines the
meaning of one construct in terms of another construct. The compiler
substitutes the new construct for the original. The purpose of macros is to
allow programmers to extend the Dylan language, for example by creating new
control structures or new definitions. Unlike C, Dylan does not intend macros
to be used to optimize code by inlining. Other parts of the language, such as
sealing and define constant, address that need.
Throughout this chapter, italic font and SMALL CAPS are used to indicate
references to the formal grammar given in Appendix A, “BNF.”
Overview 141
Macros
A macro definition describes both the syntax of a macro call and the process for
creating a new construct to replace the macro call. Typically the new construct
contains portions of the old one, which can be regarded as arguments to the
macro. A macro definition consists of a sequence of rewrite rules. The
left-hand side of each rule is a pattern that matches a macro call. The
right-hand side is a template for the expansion of a matching call. Pattern
variables appearing in the left-hand side act as names for macro arguments.
Pattern variables appearing in the right-hand side substitute arguments into
the expansion. Macro arguments can be constrained to match specified
elements of the Dylan grammar. Auxiliary rule sets enhance the rewrite rule
notation with named subrules.
Some implementations and a future version of the Dylan language
specification might allow macro expansions to be produced by compile-time
computation using the full Dylan language and an object-oriented
representation for programs. Such a “procedural macro” facility is not part of
Dylan at this time.
The input to, and output from, macro expansion is a fragment, which is a
sequence of elementary fragments. An elementary fragment is one of the
following:
■ A token: the output of the lexical grammar. The bracket tokens (, ), [, ], {,
}, #(, and #[ are not allowed. Core reserved words (except otherwise),
BEGIN-WORDS, and FUNCTION-WORDS are not allowed unless quoted with
backslash.
■ A bracketed fragment: balanced brackets ( (), [], or {} ) enclosing a
fragment.
■ A macro call fragment: a macro call.
■ A parsed fragment: a single unit that is not decomposable into its
component tokens. It has been fully parsed by the phrase grammar. A
parsed fragment is either an expression, a definition, or a local declaration.
The second and third phases of compilation (parsing and macro expansion) are
interleaved, not sequential. The parsing phase of the compiler parses a macro
call just enough to find its end. See definition-macro-call, statement,
function-macro-call, body-fragment, list-fragment, and basic-fragment in Appendix
A, “BNF.” This process of parsing a macro call also parses any macro calls
nested inside it. The result is a macro call fragment.
142 Overview
C H A P T E R 1 0
Macros
This loose grammar for macro calls gives users a lot of flexibility to choose the
grammar that their macros will accept. For example, the grammar of macro
calls doesn't care whether a bracketed fragment will be interpreted as an
argument list, a parameter list, a set of for clauses, or a module import list.
The compiler can compute the expansion of a macro call fragment immediately,
or delay computing it until it is needed. When the compiler computes the
expansion of a macro call fragment, it obeys the macro's definition. Constraints
on pattern variables can cause reparsing of portions of the macro call.
A constituent, operand, or leaf that is a macro call expands the macro some time
before the definition processing and optimization phases. The compiler
brackets the expansion in begin … end, using the standard binding of begin
in the Dylan module, and then reparses it as a statement. This reparsing may
discover more macro calls. A parse error while reparsing a macro expansion
could indicate an invalid macro definition or an incorrect call to the macro that
was not detected during pattern matching. Once the cycle of macro expansion
and reparsing has been completed, no tokens, bracketed fragments, or macro
call fragments remain and the entire source record has become one parsed
fragment.
This begin … end bracketing ensures that the expansion of a macro call will
not be broken apart by operator precedence rules when the macro call is a
subexpression. Similarly it ensures that the scopes of local declarations
introduced by a macro will not extend outside that macro expansion when the
macro call is a statement in a body.
The fragment produced by parsing a macro call, which is the input to macro
expansion, looks like this:
■ Local declarations and special definitions are parsed fragments.
■ Calls to macros are macro call fragments.
■ List constants and vector constants are parsed expression fragments.
■ Anything in brackets is a bracketed fragment.
■ If the macro call was not the result of macro expansion, everything else is
represented as sequences of tokens. There are a few restrictions on the
tokens, for example semicolons must appear in certain places and bare
brackets cannot appear; for details see the definition of body-fragment and
list-fragment in Appendix A, “BNF.”
Overview 143
C H A P T E R 1 0
Macros
■ In a macro call that is the result of macro expansion, additional items can be
parsed fragments, due to pattern-variable substitution.
■ Many built-in macros expand into implementation-specific parsed
fragments.
The parser recognizes parsed fragments as well as raw tokens. The
nonterminals expression, definition, and local-declaration in the phrase grammar
accept parsed fragments of the same kind. The nonterminal constant accepts
parsed expression fragments that are constants. The nonterminals
ORDINARY-NAME and NAME accept parsed expression fragments that are named
value references. The nonterminal operand accepts all parsed expression
fragments. The nonterminals macro, definition-macro-call, statement, and
function-macro-call accept macro call fragments.
Extensible Grammar 10
There are three kinds of macros: definition macros, which extend the available
set of definitions; statement macros, which extend the available set of
statements; and function macros, which syntactically resemble function calls
but are more flexible. Named value references and local declarations cannot be
macro calls. Only statements, function calls, and definitions are extensible.
Definition Macros 10
A definition macro extends the definition-macro-call production of the Dylan
phrase grammar to recognize additional constructs as valid definitions, by
creating a new DEFINE-BODY-WORD that is recognized by the following grammar
line:
definition-macro-call:
define modifiersopt DEFINE-BODY-WORD body-fragmentopt definition-tail
or by creating a new DEFINE-LIST-WORD that is recognized by the following
grammar line:
definition-macro-call:
define modifiersopt DEFINE-LIST-WORD list-fragmentopt
Macros
Statement Macros 10
A statement macro extends the statement production of the Dylan phrase
grammar to recognize additional constructs as valid statements, by creating a
new BEGIN-WORD that is recognized by the following grammar line:
statement:
BEGIN-WORD body-fragment end-clause
opt
The new BEGIN-WORD becomes a reserved word in each module where the
macro definition is visible. It can only be used at the beginning and end of this
new statement.
Function Macros 10
A function macro extends the function-macro-call production of the Dylan
phrase grammar to recognize additional constructs, by creating a new
FUNCTION-WORD that is recognized by the following two grammar lines:
function-macro-call:
FUNCTION-WORD ( body-fragment )
opt
FUNCTION-WORD ( body-fragment ) := expression
opt
The new FUNCTION-WORD becomes a reserved word in each module where the
macro definition is visible. It can only be used at the beginning of a macro call.
A function-macro-call containing an assignment operator,
Macros
becomes
Macro Names 10
A macro is named by a constant module binding. The macro is available to be
called in any scope where this binding is accessible. Macro names can be
exported and can be renamed during module importing just like any other
module binding. Macro bindings are constant and cannot be changed by the
assignment operator :=.
The name bound to a definition macro is the macro’s DEFINE-BODY-WORD or
DEFINE-LIST-WORD suffixed by “-definer”. This suffixing convention is
analogous to the naming convention for setters and allows the
DEFINE-BODY-WORD or DEFINE-LIST-WORD to be used for another purpose. The
name bound to a statement macro is the macro's BEGIN-WORD. The name
bound to a function macro is the macro's FUNCTION-WORD.
A named value reference is not allowed when the value of the binding is a
macro, because macros are not run-time objects.
A macro cannot be named by a local binding. Macro definitions are always
scoped to modules.
Macros
Rewrite Rules 10
The grammar of a macro definition is define macro macro-definition. For
details see Appendix A, “BNF.”
If the optional NAME at the end of a macro-definition is present, it must be the
same NAME that appears at the beginning of the macro-definition.
The kind of macro being defined, and thus the Dylan grammar production that
this macro extends, is determined by which kind of rules appear in the macro’s
main-rule-set.
The NAME preceding the main-rule-set is the name of the binding whose value
is this macro. It must be consistent with each left-hand side of the
Macros
Patterns 10
Approximately speaking, a pattern looks like the construct that it matches, but
contains pattern variables that bind to portions of the construct. Hence a
left-hand side in the main-rule-set looks like a macro call. However, the
grammar of patterns is not the same as the grammar of programs, but contains
just what is required to match the portions of the Dylan grammar that are
extensible by macros. Patterns have a simple nested grammar, with
148 Patterns
C H A P T E R 1 0
Macros
semicolons, commas, and brackets used to indicate levels of nesting. See the
definition of pattern in Appendix A, “BNF.”
A pattern matches a fragment (a sequence of elementary fragments) by
executing the following algorithm from left to right. It is easy to create patterns
that are ambiguous when considered as grammars. This ambiguity is resolved
by the left to right processing order and the specified try-shortest-first order for
matching wildcards. Pattern matching succeeds only if all sub-patterns match.
If pattern matching fails, the current rule fails and control passes to the next
rule in the current rule set. If all patterns in a rule set fail to match, the macro
call is invalid.
Multiple occurrences of the same pattern variable name in a single rule's
left-hand side are not valid.
A pattern matches a fragment as follows:
■ If the pattern consists of just one pattern-list, go to the next step. Otherwise
divide the pattern into subpatterns and the fragment into subfragments at
semicolons, and match subpatterns to subfragments individually in order.
The subpatterns and subfragments do not include the semicolons that
separate them. Suppose the pattern consists of N + 1 pattern-lists separated
by N semicolons. Locate the first N semicolons in the fragment (without
looking inside of elementary fragments) and divide up the fragment into
subfragments accordingly. The match fails if the fragment contains fewer
than N - 1 semicolons. As a special case, if the fragment contains N - 1
semicolons, the match still succeeds and the last subfragment is empty. If
the fragment contains more than N semicolons, the extra semicolons will be
in the last subfragment.
A pattern-list matches a fragment as follows:
■ If the pattern-list consists of just a pattern-sequence, go to the next step. If
the pattern-list consists of just a property-list-pattern, go to that step.
Otherwise divide the pattern-list into subpatterns and the fragment into
subfragments at commas, and match subpatterns to subfragments
individually in order. The subpatterns and subfragments do not include the
commas that separate them. Suppose the pattern consists of N + 1
subpatterns separated by N commas. Locate the first N commas in the
fragment (without looking inside of elementary fragments) and divide up
the fragment into subfragments accordingly. The match fails if the fragment
contains fewer than N - 1 commas. As a special case, if the fragment contains
N - 1 commas, the match still succeeds and the last subfragment is empty. If
Patterns 149
C H A P T E R 1 0
Macros
the fragment contains more than N commas, the extra commas will be in the
last subfragment. Note that the subdivision algorithms for commas and
semicolons are identical.
A pattern-sequence matches a fragment as follows:
■ Consider each simple-pattern in the pattern-sequence in turn from left to
right. Each simple-pattern matches an initial subsequence of the fragment
and consumes that subsequence, or fails. The entire pattern match fails if
any simple-pattern fails, if the fragment is empty and the simple-pattern
requires one or more elementary fragments, or if the fragment is not entirely
consumed after all simple-patterns have been matched. There is a special
backup and retry rule for wildcards, described below.
A simple-pattern matches a fragment as follows:
■ A NAME or => consumes one elementary fragment, which must be identical
to the simple-pattern. A NAME matches a name that is spelled the same,
independent of modules, lexical scoping issues, alphabetic case, and
backslash quoting. As a special case, after the word otherwise, an => is
optional in both the pattern and the fragment. Presence or absence of the
arrow in either place makes no difference to matching.
■ A bracketed-pattern matches and consumes a bracketed-fragment. If the
enclosed pattern is omitted, the enclosed body-fragment must be empty,
otherwise the enclosed pattern must match the enclosed body-fragment
(which can be empty). The type of brackets ( (), [], or {} ) in the
bracketed-fragment must be the same as the type of brackets in the
bracketed-pattern.
A binding-pattern matches a fragment as follows:
■ pattern-variable :: pattern-variable consumes as much of the fragment as
can be parsed by the grammar for variable. It matches the first
pattern-variable to the variable-name and the second to the type, a parsed
expression fragment. If no specializer is present, it matches the second
pattern-variable to a parsed expression fragment that is a named value
reference to <object> in the Dylan module. This matching checks the
constraints on the pattern variable, fails if the constraint is not satisfied, and
binds the pattern variable to the fragment.
■ pattern-variable = pattern-variable consumes as much of the fragment as can
be parsed by the grammar for variable = expression. It matches the first
150 Patterns
C H A P T E R 1 0
Macros
Patterns 151
C H A P T E R 1 0
Macros
152 Patterns
C H A P T E R 1 0
Macros
Patterns 153
C H A P T E R 1 0
Macros
Macros
Notes:
1. Where expression, operand, constituents or body appears in the grammar that
this constraint accepts, the bound fragment contains a parsed expression
fragment, not the original elementary fragments.
2. Parsing stops at an intermediate word.
3. The body is wrapped in begin … end to make it an expression, using the
standard binding of begin in the Dylan module. An empty body defaults
to #f.
4. A pattern-variable with a macro constraint accepts exactly one elementary
fragment, which must be a macro call fragment. It binds the pattern variable
to the expansion of the macro.
Some implementations and a future version of the Dylan language
specification might add more constraint choices to this table.
When a pattern variable has the same name as an auxiliary rule-set, its
constraint defaults to wildcard and can be omitted. Otherwise a constraint
must be specified in every pattern-variable and pattern-keyword.
Macros
Intermediate Words 10
When a pattern-variable has a constraint of body or case-body, its parsing of
the fragment stops before any token that is an intermediate word. This allows
intermediate words to delimit clauses that have separate bodies, like else and
elseif in an if statement. The intermediate words of a macro are identified
as follows:
■ Define a body-variable to be a pattern variable that either has a constraint of
body or case-body, or names an auxiliary rule-set where some left-hand
side in that rule-set ends in a body-variable. This is a least fixed point, so a
recursive auxiliary rule-set does not automatically make its name into a
body-variable! Note that an ellipsis that stands for a pattern variable is a
body-variable when that pattern variable is one.
■ Define an intermediate-variable to be a pattern variable that either
immediately follows a body-variable in a left-hand side, or appears at the
beginning of a left-hand side in an auxiliary rule-set named by an
intermediate-variable.
■ An intermediate word is a NAME that either immediately follows a
body-variable in a left-hand side, or occurs at the beginning of a left-hand
side in an auxiliary rule-set named by an intermediate-variable.
Intermediate words are not reserved, they are just used as delimiters during
the parsing for a pattern-variable with a body or case-body constraint.
Templates 10
Approximately speaking, a template has the same structure as what it
constructs, but contains pattern variables that will be replaced by fragments
extracted from the macro call. Thus a template in the main-rule-set looks like
the macro expansion.
However, templates do not have a full grammar. A template is essentially any
sequence of tokens and substitutions in which all of Dylan’s brackets are
156 Templates
C H A P T E R 1 0
Macros
balanced: (), [], {}, #(), and #[]. Substitution for pattern variables
produces a sequence of tokens and other elementary fragments.
Note that using unparsed token sequences as templates allows a macro
expansion to contain macro calls without creating any inter-dependencies
between macros. Since the template is not parsed at macro definition time, any
macros called in the template do not have to be defined first, and macros can be
compiled independently of each other. This simplifies the implementation at
the minor cost of deferring some error checking from when a macro is defined
until the time when the macro is called.
The grammar for templates is the definition of template in “Templates” on
page 415.
All template-elements other than substitution are copied directly into the macro
expansion. The various kinds of substitution insert something else into the
macro expansion, as follows:
? NAME The fragment bound to the pattern variable named NAME.
name-prefixopt ? name-string-or-symbol name-suffixopt
The fragment bound to the pattern variable named
name-string-or-symbol, converted to a string or symbol and/or
concatenated with a prefix and/or suffix. Note that this rule
applies only when the first rule does not. The fragment must be
a NAME. Concatenate the prefix, if any, the characters of the
fragment, and the suffix, if any. The alphabetic case of the
characters of the fragment is unspecified. Convert this to the
same grammatical type (NAME, STRING, or SYMBOL) as
name-string-or-symbol. When the result is a NAME, its hygiene
context is the same as that of the fragment.
?? NAME separatoropt ...
The sequence of fragments bound to the pattern variable named
NAME, with separator inserted between each pair of fragments.
The pattern variable must have been bound by a ??
pattern-keyword. Separator can be a binary operator, comma, or
semicolon. If the size of the sequence is 1 or separator is omitted,
no separator is inserted. If the sequence is empty, nothing is
inserted.
... The fragment bound to the pattern variable that names this rule
set; this is only valid in an auxiliary rule set.
Templates 157
C H A P T E R 1 0
Macros
Macros
The ellipsis ... in patterns and templates of an auxiliary rule set means
exactly the same thing as the pattern variable that is rewritten by this auxiliary
rule set. Using ellipsis instead of the pattern variable can make recursive
rewrite rules more readable.
Hygiene 10
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 to be
replaced in the macro expansion by a special token which plays the same
grammatical role as a NAME but remembers three pieces of information:
■ The original NAME.
■ The lexical context where the macro was defined, which is just a module
since macro definitions are only allowed at top level, not inside of bindings.
Hygiene 159
C H A P T E R 1 0
Macros
160 Hygiene
C H A P T E R 1 0
Macros
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.
Implementations must use some automatic mechanism for marking the
bindings potentially referenced by macro expansions and must make such
bindings available to any library where the macro is accessible. In general one
cannot tell when a macro is defined what bindings are going to be referenced
by macro expansions, because the right-hand sides of rewrite rules are not fully
parsed until after a macro is called and expanded. However, an upper bound
on this set of bindings can be computed.
Statement Macros 10
Begin 10
Macros
Block 10
abody:
{ ?main:body afterwards ?after:body }
=> { with-afterwards(method() ?main end, method () ?after
end) }
{ ?main:body }
=> { ?main }
excp:
{ ?type:expression } => { ?type }
{ ?:name :: ?type:expression } => { ?type, condition: ?name }
end;
Macros
Case 10
For 10
Macros
by:
{ by ?step:expression } => { ?step }
{ } => { 1 }
end;
Macros
// while:/until: clause
{ for-clause(?e:expression stop) }
=> { , stop2: ?e }
// Collection clause
{ for-clause(?v:variable in ?c:expression) }
=> { , init0: [ let collection = ?c;
let (initial-state, limit,
next-state, finished-state?,
current-key, current-element)
= forward-iteration-protocol(collection);
]
, var1: state, init1: initial-state
, next1: next-state(collection, state)
, stop1: finished-state?(collection, state, limit)
, var2: ?v, next2: current-element(collection, state) }
Macros
clauses:
{ ?clause:macro ... } => { ?clause ... }
{ } => { }
end;
Macros
Macros
If 10
define macro if
{ if (?test:expression) ?:body ?elses end }
=> { case ?test => ?body;
otherwise ?elses end }
elses:
{ elseif (?test:expression) ?:body ... }
=> { case ?test => ?body;
otherwise ... end }
{ else ?:body } => { ?body }
{ } => { #f }
end;
Method 10
Select 10
what:
{ ?object:expression by ?compare:expression }
=> { let object = ?object;
let compare = ?compare
}
{ ?object:expression } => { let object = ?object;
let compare = \== }
Macros
case-body:
{ otherwise ?:body } => { ?body }
{ } => { error("select error") }
{ ?keys => ?:body ... } => { if (?keys) ?body
else ... end if }
keys:
{ ?key:expression } => { compare(?key, object) }
{ ?key:expression, ... } => { compare(?key, object) |
... }
end;
Unless 10
Until 10
Macros
While 10
Definition Macros 10
Define Class 10
supers:
{ ?super:expression, ... } =>
{ } =>
Macros
Define Constant 10
Define Domain 10
types:
{ ?type:expression, ... } => { ?type, ... }
{ } => { }
end;
Define Generic 10
rest:
{ ( ?parameters:* ), #key } =>
{ ( ?parameters:* ) => ?:variable, #key } =>
{ ( ?parameters:* ) => (?variables:*), #key } =>
end;
Define Library 10
items:
{ use ?:name, #rest ?options:*; ... } =>
{ export ?names; ... } =>
{ } =>
Macros
names:
{ ?:name } =>
{ ?:name, ... } =>
end;
Define Method 10
rest:
{ (?parameters:*) => (?results:*) ; ?:body } =>
{ (?parameters:*) => (?results:*) ?:body } =>
{ (?parameters:*) => ?result:variable ; ?:body } =>
{ (?parameters:*) ; ?:body } =>
{ (?parameters:*) ?:body } =>
end;
Define Module 10
items:
{ use ?:name, #rest ?options:*; ... } =>
{ export ?names; ... } =>
{ create ?names; ... } =>
{ } =>
names:
{ ?:name } =>
{ ?:name, ... } =>
end;
Macros
Define Variable 10
Additional Examples 10
The following macros are not built-in, but are simply supplied as examples.
Each is shown as a definition followed by a sample call.
test(foo.bar) := foo.baz;
Macros
Transform! 10
Formatting-table 10
Macros
With-input-context 10
bbody:
{ ?:body ?clauses } => { list(?clauses), method() ?body end }
clauses:
{ } => { }
{ on (?:name :: ?spec:expression, ?type:variable) ?:body ... }
=> { pair(?spec, method (?name :: ?spec, ?type) ?body end),
... }
end macro;
Define Command 10
Macros
arguments:
{ ?:variable = ?default:expression ?stuff:*, ?key-arguments }
=> { #key ?variable = ?default, ?key-arguments }
{ ?argument, ... } => { ?argument, ... }
{ } => { }
Macros
Macros
Get-resource 10
// The idea is that in this application each library has its own
// variable named $library, which is accessible to modules in
that
// library. Get-resource gets a resource associated with the
library
// containing the call to it. Get-resource-from-library is a
function.
// The get-resource macro is a device to make programs more
concise.
show-icon(get-resource(ResType("ICON"), 1044));
Completing-from-suggestions 10
Macros
#rest ?options:expression)
?:body end }
=>{ complete-input(?stream,
method (?=suggest) ?body end,
?options) }
end macro;
Define Jump-instruction 10
Macros
Contents
Overview 183
Objects 183
Types 185
Types 185
Classes 186
Singletons 189
Simple Objects 190
Characters 190
Symbols 191
Booleans 192
Numbers 192
Numbers 192
Complex Numbers 193
Reals 194
Floats 195
Rationals 197
Integers 197
Collections 199
Collections 199
Explicit Key Collections 202
Sequences 202
Mutable Collections 205
Stretchy Collections 209
Arrays 210
Vectors 212
Deques 216
Contents 181
Lists 218
Ranges 221
Strings 223
Tables 226
Functions 229
Functions 229
Generic Functions 231
Methods 233
Conditions 234
Conditions 234
Serious Conditions 236
Errors 236
Warnings 238
Restarts 240
Aborts 242
182 Contents
C H A P T E R 1 1
Overview 11
This chapter contains an entry for every class defined by Dylan.
The superclasses listed for a class C are those classes defined by the Dylan
language from which C most directly inherits. They are not required to be the
direct superclasses of C, because implementations are free to insert
implementation-defined classes in the class hierarchy. However, any classes
defined by Dylan which appear in the class precedence list of C must appear in
the same order in which they would appear if the specified superclasses were
the direct superclasses of C, in the order given.
All classes are specified as open or sealed. A class may be specifed as abstract;
if it is not, then it is concrete. A class may be specified as primary; if it is not,
than it is free. A class may be specified as instantiable. If it is not, then it is
uninstantiable. Chapter 9, “Sealing,” contains a complete description of these
characteristics.
An implementation may choose to impose fewer restrictions than specified. For
example, a class specified as sealed may be left open, and a class specified as
primary may be left free. However, any program which takes advantage of this
liberality will not be portable.
Each class entry includes tables of operations defined on the class. These tables
are cross references to Chapter 12, “The Built-In Functions,” and represent
redundant information. A function, generic function, or method is listed under
a class if one of its arguments is specialized on the class. In addition,
constructors are listed. Not all generic functions which specialize on <object>
are listed.
Objects 11
Overview 183
Init-keywords: None.
Description: The class <object> is the root of the type system. All objects are general
instances of <object>, all types are subtypes of <object>, and all classes are
subclasses of <object>.
184 Objects
C H A P T E R 1 1
Types 11
Types 11
Superclasses: <object>
Init-keywords: None.
Types 185
C H A P T E R 1 1
Description: The class of all types. All types (including <type> and <class>) are instances
of <type>.
Classes 11
Superclasses: <type>
186 Types
C H A P T E R 1 1
Types 187
C H A P T E R 1 1
Description: The class of all classes. All classes (including <class>) are general instances of
<class>.
In most programs the majority of classes are created with define class.
However, there is nothing to prevent programmers from creating classes by
calling make, for example, if they want to create a class without storing it in a
module binding, or if they want to create new classes at runtime.
If make is used to create a new class and creating the new class would violate
any restrictions specified by sealing directives, then an error of type
<sealed-object-error> is signaled.
188 Types
C H A P T E R 1 1
Singletons 11
Superclasses: <type>
Types 189
C H A P T E R 1 1
Operations: None.
Simple Objects 11
Characters 11
Superclasses: <object>
Init-keywords: None.
Symbols 11
Superclasses: <object>
Init-keywords: None.
Booleans 11
Superclasses: <object>
Init-keywords: None.
Operations: None.
Description: The class of boolean values. The literal constants #t and #f are general
instances of <boolean>. Note that for the purposes of conditional
expressions, all objects besides #f count as true. (This does not imply any
other objects are instances of <boolean>.)
Numbers 11
Numbers 11
Superclasses: <object>
Init-keywords: None.
Operations: None.
192 Numbers
C H A P T E R 1 1
Complex Numbers 11
Superclasses: <number>
Init-keywords: None.
Description: The sealed superclass of all built-in numbers, including real numbers. There
are no non-real subclasses of <complex> defined by the language, but
implementations may define such subclasses. Because <complex> and all its
defined subclasses are sealed, implementation-defined subclasses may be
added efficiently.
Many built-in functions are defined to have methods on <complex>. This
means that the function is defined on all built-in subclasses of <complex>. It
does not imply that there is a single method specialized on the <complex>
class.
Operations: The class <complex> provides implementations for the following functions:
Numbers 193
C H A P T E R 1 1
Reals 11
Superclasses: <complex>
Init-keywords: None.
Operations: The class <real> provides implementations for the following functions:
194 Numbers
C H A P T E R 1 1
Floats 11
The classes <single-float> and <double-float> are intended but not
required to be the corresponding IEEE types. The class <extended-float> is
intended but not required to have more range and/or precision than
<double-float>.
If an implementation has fewer than three floating point classes, the names
<single-float>, <double-float> and <extended-float> may all refer
to the same object.
Numbers 195
C H A P T E R 1 1
Superclasses: <real>
Init-keywords: None.
Description: The class of all floating-point numbers. This class is abstract. All floating point
numbers will be instances of some concrete subclass of this class.
Operations: None.
Superclasses: <float>
Init-keywords: None.
Description: The class of single-precision floating-point numbers. This class is intended but
not required to correspond to IEEE single-precision.
Operations: None.
Superclasses: <float>
Init-keywords: None.
Description: The class of double-precision floating-point numbers. This class is intended but
not required to correspond to IEEE double-precision.
Operations: None.
196 Numbers
C H A P T E R 1 1
Superclasses: <float>
Init-keywords: None.
Operations: None.
Rationals 11
Superclasses: <real>
Init-keywords: None.
Operations: None.
Integers 11
Superclasses: <rational>
Init-keywords: None.
Numbers 197
C H A P T E R 1 1
198 Numbers
C H A P T E R 1 1
Collections 11
This section describes collections, Dylans aggregate data structures.
An overview of collections is given in Chapter 8, “Collections.”
Collections 11
Superclasses: <object>
Init-keywords: None.
Collections 199
C H A P T E R 1 1
200 Collections
C H A P T E R 1 1
Collections 201
C H A P T E R 1 1
Superclasses: <collection>
Init-keywords: None.
Sequences 11
The class of collections whose keys are consecutive integers starting from zero.
Superclasses: <collection>
Init-keywords: None.
Description: The class of collections whose keys are consecutive integers starting from zero.
202 Collections
C H A P T E R 1 1
Sequences must be stable under iteration, and the iteration order must match
the order of keys. Thus, the key associated with a sequence’s iteration state can
be determined by keeping a counter in parallel with the iteration state.
The default methods for add, add-new, remove, choose, choose-by,
intersection, union, remove-duplicates, copy-sequence,
concatenate, reverse, and sort all return new sequences that are
instances of the type-for-copy of their primary sequence argument.
However, more specialized methods are permitted to choose a more
appropriate result class; for example, copy-sequence of a range returns
another range, even though the type-for-copy value of a range is the
<list> class.
<sequence> is disjoint from <explicit-key-collection> because of the
inert domain over the function key-test for <sequence>.
The element type of <sequence> is indefinite ⇐ <object>.
Collections 203
C H A P T E R 1 1
Function Page
add Adds an element to a sequence. 296
add! Adds an element to a sequence. 297
add-new Adds a new element to a sequence. 298
add-new! Adds a new element to a sequence. 299
remove Removes an element from a sequence. 300
remove! Removes an element from a sequence. 300
choose Returns those elements of a sequence 321
that satisfy a predicate.
choose-by Returns those elements of a sequence 322
that correspond to those in another
sequence that satisfy a predicate.
intersection Returns the intersection of two sequences. 307
union Returns the union of two sequences. 308
remove-duplicates Returns a sequence without duplicates. 309
remove-duplicates Returns a sequence without duplicates. 310
!
copy-sequence Returns a freshly allocated copy of some 311
subsequence of a sequence.
replace-subsequen Replaces a portion of a sequence with the 313
ce! elements of another sequence.
reverse Returns a sequence with elements in the 303
reverse order of its argument sequence.
reverse! Returns a sequence with elements in the 304
reverse order of its argument sequence.
sort Returns a sequence containing the 305
elements of its argument sequence,
sorted.
204 Collections
C H A P T E R 1 1
Function Page
sort! Returns a sequence containing the 306
elements of its argument sequence,
sorted.
last Returns the last element of a sequence. 293
subsequence-posit Returns the position where a pattern 314
ion appears in a sequence.
Mutable Collections 11
Superclasses: <collection>
Init-keywords: None.
Collections 205
C H A P T E R 1 1
206 Collections
C H A P T E R 1 1
Init-keywords: None.
Init-keywords: None.
Collections 207
C H A P T E R 1 1
208 Collections
C H A P T E R 1 1
Stretchy Collections 11
Superclasses: <collection>
Init-keywords: None.
Description: The class of collections that may grow or shrink to accomodate adding or
removing elements.
Stretchy collections allow element-setter to be called with a key that is not
present in the collection, expanding the collection as necessary to add a new
element in that case. Each concrete subclass of <stretchy-collection>
must provide or inherit a method for element-setter that behaves as
follows when there is not already an element present for the indicated key:
■ If the class is a subclass of <explicit-key-collection>, adds a new
element to the collection with the indicated key.
■ If the class is a subclass of <sequence>, first calls size-setter on the
key + 1 and the collection to expand the sequence. The key must be a
non-negative integer.
The element type of <stretchy-collection> is indefinite ⇐
<object>.
Collections 209
C H A P T E R 1 1
Arrays 11
Superclasses: <mutable-sequence>
Description: The class of collections whose elements are arranged according to a Cartesian
coordinate system.
An array element is referred to by a (possibly empty) series of indices. The
length of the series must equal the rank of the array. Each index must be a
non-negative integer less than the corresponding dimension. An array element
may alternatively be referred to by an integer, which is interpreted as a
row-major index.
Arrays typically use space efficient representations, and the average time
required to access a randomly chosen element is typically sublinear to the
number of elements.
Whe a multi-dimensional array is created, the concrete class that is actually
instantiated cannot be any of the specified subclasses of <array>, which are all
one-dimensional. Every implementation must have one or more concrete
subclasses of <array> that are used for this purpose. These concrete
subclasses have no specified names, and their names are not exported by the
Dylan module.
210 Collections
C H A P T E R 1 1
Collections 211
C H A P T E R 1 1
Vectors 11
Superclasses: <array>
212 Collections
C H A P T E R 1 1
Superclasses: <vector>
Collections 213
C H A P T E R 1 1
214 Collections
C H A P T E R 1 1
The class of simple vectors that may have elements of any type.
Superclasses: <simple-vector>
Operations: None.
Collections 215
C H A P T E R 1 1
Deques 11
216 Collections
C H A P T E R 1 1
Description: A subclass of sequence that supports efficient forward and backward iteration,
and efficient addition and removal of elements from the beginning or end of
the sequence.
Because <deque> is abstract and instantiable but has no specified subclasses,
every implementation must provide one or more concrete subclass to
instantiate. These concrete subclasses have no specified names, and their names
are not exported by the Dylan module.
The element type of <deque> is indefinite ⇐ <object>.
Collections 217
C H A P T E R 1 1
Lists 11
Lists are constructed by linking together instances of <pair>. The head of a list
contains an element, and the tail of the list contains a pointer to the next pair in
the list. The list ends when the tail of a pair contains something besides another
pair.
A proper list has a final pair with a tail containing the empty list.
An improper list does not have a final pair with a tail containing the empty
list, either because the tail of its final pair is not the empty list, or because the
list is circular and thus does not have a final pair. Except when their behavior
on improper lists is documented explicitly, collection or sequence functions are
not guaranteed to return an answer when an improper list is used as a
collection or a sequence. At the implementation’s option, these functions may
return the correct result, signal a <type-error>, or (in the case of a circular
list) fail to return.
When treated as a collection, the elements of a list are the heads of successive
pairs in the list.
Superclasses: <mutable-sequence>
218 Collections
C H A P T E R 1 1
Collections 219
C H A P T E R 1 1
Superclasses: <list>
Init-keywords: None.
Description: The class of lists that can have new values assigned to their heads and tails.
The element type of <pair> is <object>.
220 Collections
C H A P T E R 1 1
Superclasses: <list>
Init-keywords: None.
Description: The class <empty-list> has only one instance, the empty list. The empty list
is a direct instance of <empty-list> and an indirect instance of <list>.
Note that <empty-list> is not == to singleton (#()).
The element type of <empty-list> is <object>.
Operations: None.
Ranges 11
Superclasses: <sequence>
Collections 221
C H A P T E R 1 1
Description: The class <range> is used for creating sequences of numbers. Ranges may be
infinite in size, and may run from higher numbers to lower numbers.
Because <range> in abstract and instantiable but has no specified subclasses,
every implementation must provide one or more concrete subclass to
instantiate. These concrete subclasses have no specified names, and their names
are not exported by the Dylan module.
The element type of <range> is indefinite ⇐ <real>.
222 Collections
C H A P T E R 1 1
Strings 11
Superclasses: <mutable-sequence>
Collections 223
C H A P T E R 1 1
Description: The class <byte-string> represents strings with elements that are eight bit
characters. It provides constant time element and element-setter
methods.
The element type of <byte-string> is indefinite ⇐ K2 (where K2 is a
subtype of <character>).
224 Collections
C H A P T E R 1 1
The class of vectors with elements that are sixteen-bit Unicode characters.
Description: The class <unicode-string> represents strings with elements that are
sixteen bit Unicode characters. It provides constant time element and
element-setter methods.
The element type of <unicode-string> is indefinite ⇐ K1 (where K1 is
a subtype of <character>).
Collections 225
C H A P T E R 1 1
Tables 11
Also called a hash table, a table is an unordered mapping between arbitrary
keys and elements. Tables are the only predefined collections that are unstable
under iteration.
Tables are stretchy in that they allow the addition and removal of keys.
<table> and its subclasses are the only predefined classes that are stretchy but
are not stretchy sequences.
For a complete description of tables, see “Tables” on page 120.
226 Collections
C H A P T E R 1 1
Collections 227
C H A P T E R 1 1
Superclasses: <table>
Init-keywords: None.
228 Collections
C H A P T E R 1 1
Functions 11
Functions 11
Superclasses: <object>
Init-keywords: None.
Description: All functions are instances of <function>. Functions are described in Chapter
6, “Functions.”
Functions 229
C H A P T E R 1 1
230 Functions
C H A P T E R 1 1
Generic Functions 11
Superclasses: <function>
Functions 231
C H A P T E R 1 1
Description: The class of generic functions. Generic functions are described in Chapter 6,
“Functions.”
The arguments describe the shape of the generic function’s parameter list, and
thereby control which methods can be added to the generic function. See the
section “Kinds of Parameter Lists” on page 84 and the section “Parameter List
Congruency” on page 91 for the implications of these choices.
An error is signaled if the value of rest?: is true and the value of key: is a
collection. While a method parameter list may specify both #rest and #key, a
generic function parameter list cannot.
An error is signaled if the value of all-keys?: is true and the value of key:
is #f.
A new generic function initially has no methods. An error will be signaled if a
generic function is called before methods are added to it. Once a generic
function is created, you can give it behavior by adding methods to it with
add-method or define method.
Generic functions are not usually created by calling make directly. Most often
they are created by define generic or implicitly by define method.
232 Functions
C H A P T E R 1 1
Methods 11
Superclasses: <function>
Init-keywords: None.
Functions 233
C H A P T E R 1 1
Conditions 11
Conditions 11
The class of objects used by the condition system to connect a signaler with an
appropriate handler.
Superclasses: <object>
Init-keywords: None.
234 Conditions
C H A P T E R 1 1
Conditions 235
C H A P T E R 1 1
Serious Conditions 11
Superclasses: <condition>
Init-keywords: None.
Errors 11
The class of conditions that represent something invalid about the program.
Superclasses: <serious-condition>
Init-keywords: None.
236 Conditions
C H A P T E R 1 1
Operations: None.
The class of error conditions that consist of just an error message constructed
from a format string and arguments.
Superclasses: <error>
Init-keywords: format-string:
An instance of <string>. A format string describing the error.
format-arguments:
An instance of <sequence>. Format arguments to splice into
the format string to describe the error.
Description: The class of error conditions that consist of just an error message constructed
from a format string and arguments.
The recovery protocol of <simple-error> is empty.
Superclasses: <error>
Init-keywords: value: An instance of <object>. The object whose type was checked.
Conditions 237
C H A P T E R 1 1
type: An instance of <type>. The type which was expected. The error
was signaled because the object was not of this type.
Description: The class of errors indicating that an object was not of the expected type.
The recovery protocol is empty.
Superclasses: <error>
Init-keywords: None.
Description: The class of errors that indicate the violation of a sealing restriction.
Operations: None.
Warnings 11
The class of conditions that are interesting to users but can safely be ignored.
Superclasses: <condition>
238 Conditions
C H A P T E R 1 1
Init-keywords: None.
Superclasses: <warning>
IInit-keywords: format-string:
An instance of <string>. A format string describing the
warning.
format-arguments:
An instance of <sequence>. Format arguments to splice into
the format string to describe the warning.
Conditions 239
C H A P T E R 1 1
Restarts 11
Superclasses: <condition>
240 Conditions
C H A P T E R 1 1
Superclasses: <restart>
Init-keywords: format-string:
An instance of <string>. A format string describing the restart.
format-arguments:
An instance of <sequence>. Format arguments to splice into
the format string to describe the restart.
Conditions 241
C H A P T E R 1 1
Aborts 11
Superclasses: <restart>
Init-keywords: None.
Operations: None.
242 Conditions
Figure 12-0
Listing 12-0
C H A P T E R 1 2 Table 12-0
Contents
Overview 245
Constructing and Initializing Instances 246
General Constructor 246
Initialization 247
Specific Constructors 249
Equality and Comparison 254
Not and Identity 255
Equality Comparisons 255
Magnitude Comparisons 258
Arithmetic Operations 261
Properties 262
Arithmetic Operations 264
Coercing and Copying Objects 274
General Coercion Function 275
Coercing Case 277
Copying Objects 279
Collection Operations 281
Collection Properties 281
Selecting Elements 286
Adding and Removing Elements 296
Reordering Elements 303
Set Operations 307
Subsequence Operations 311
Mapping and Reducing 315
The Iteration Protocol 326
Reflective Operations on Types 331
Contents 243
244 Contents
C H A P T E R 1 2
Overview 12
This chapter contains an entry for each function defined by Dylan.
The functions described below are annotated either as an open generic
function or as a function.
A function specified as an open generic function can be extended through the
addition of programmer defined methods. The signature of the generic
function constrains which methods can be added through the congruency rules
described on page 91. The signature does not imply a set of predefined
methods. For example, the signature of + is (<object>, <object>), but
the predefined methods on + only cover subtypes of <number>. Particular
behavior of the function is given in its description and in the description of its
methods.
A function specified as a function cannot portably be extended through the
addition of methods. Implementations are free to implement these functions as
open generic functions, but programs that take advantage of such liberality will
not be portable. The signature of such a function specifies the type domain of
the function, but does not necessarily imply that the function is applicable to all
instances of the types. The exact behavior of the function is given in its
description.
Implementations are allowed to define these generic functions and functions
with signatures that are less restrictive than those given below. However,
programs that take advantage of this liberality will not be portable.
Where a sealed domain is specified, implementations are free to seal the
domain or leave the domain unsealed. Portable programs should not rely on
the domain being unsealed.
When a method is specified, it describes the behavior of a generic function
when applied to arguments of particular types. It does not imply that this
behavior is implemented by a single method.
Overview 245
General Constructor 12
Initialization 12
Values: objects Instances of <object>. The return values are ignored by make.
Description: Provides a way for users to handle initialization of instances which cannot be
expressed simply by init specifications. This is typically needed when a
computation requires inputs from multiple initialization arguments or slot
values, or a single computation needs to be used to initialize multiple slots.
By convention, all initialize methods should call next-method very early,
to make sure that any initializations from less specific classes are performed
first.
The initialize generic function permits all keywords and requires none. It
does this because the keyword argument checking is performed by the default
method on make.
Description: Returns true if the slot in instance that would be accessed by the getter generic
function is initialized. If the slot is not initialized, then false is returned.
slot-initialized? will signal an error if the getter does not access a slot in
the instance.
Specific Constructors 12
list [Function] 12
pair [Function] 12
Description: Creates a freshly allocated pair whose head value is object1 and tail value is
object2.
pair (1, 2)
⇒ #(1 . 2)
pair (1, #(2, 3, 4, 5))
⇒ #(1, 2, 3, 4, 5)
Note that while the pair returned by pair is freshly allocated, it may be the
beginning of a list, portions of which are not freshly allocated.
range [Function] 12
singleton [Function] 12
limited [Function] 12
Description: Returns a limited subtype of class. The available keyword arguments depend
on the class. Not all classes support limited; the methods for limited are
documented individually.
for fill is #f so if instance?(#f, of) is not true and size is nonzero, the
fill: initialization keyword is required because the default would cause a
type error.
All general instances of <simple-vector> provide a constant time
implementation of element and element-setter.
type-union [Function] 12
Description: Returns a type whose instances are the instances of type1 and all the more-types.
The type returned is not instantiable. A complete description of union types is
given in “Union Types” on page 71.
vector [Function] 12
~ [Function] 12
Equality Comparisons 12
== [Function] 12
Description: Returns true if object1 and object2 are identical. Otherwise, it returns false.
Objects are considered identical if they are computationally equivalent. That is,
there is no way for any possible Dylan program to distinguish them.
At an implementation level, this will usually mean that the objects are pointers
to the same storage or are the same immediate value. An extension is made for
built-in number classes and characters. Because these objects are not mutable
(i.e. cannot be changed), two with the same value will always be the same (and
will thus be indistinguishable to programs).
~== [Function] 12
Description: Returns true if object1 and object2 are not identical. It returns false if they are
identical.
If both arguments are instances of <complex> then the result is computed in
an implementation-defined way. Otherwise, the result is computed by
~(object1 == object2).
Description: Returns true if object1 and object2 are equal. Otherwise, it returns false.
Programmers may define methods for = specialized on classes they define. A
programmer may be required to provide an = method when defining
subclasses of some predefined classes in order to fullfill the protocol of the
class, as described below. For objects which do not have a more specific =
method, = returns the same as ==.
= is not guaranteed to return. For example, it may not return when called on
circular structures or otherwise unbounded structures.
The generic function = is inert over the domain (<complex>, <complex>).
~= [Function] 12
Description: Returns true if object1 and object2 are not equal. It returns false if they are equal.
If both arguments are instances of <complex> then the result is computed in
an implementation-defined way. Otherwise, the result is computed by the
expression ~(object1 = object2).
Magnitude Comparisons 12
Returns true if its first operand is less than its second operand.
> [Function] 12
Returns true if its first operand is greater than its second operand.
<= [Function] 12
Returns true if its first operand is less than or equal to its second operand.
>= [Function] 12
Returns true if its first operand is greater than or equal to its second operand.
min [Function] 12
max [Function] 12
Arithmetic Operations 12
When instances of <rational> and instances of <float> are combined by a
numerical function, the instance of <rational> is first converted to an
instance of <float> of the same format as the original instance of <float>.
Properties 12
odd? [Function] 12
even? [Function] 12
Arithmetic Operations 12
Description: Returns the negation of its argument. The unary minus operator is equivalent
to a call to the negative in the current binding environment.
floor [Function] 12
Description: Truncates real1 towards negative infinity. The integer part is returned as integer,
the remainder is returned as real2.
ceiling [Function] 12
Description: Truncates real1 towards positive infinity. The integer part is returned as integer,
the remainder is returned as real2.
round [Function] 12
Description: Rounds real1 towards towards the nearest mathematical integer. The integer
part is returned as integer, the remainder is returned as real2.
truncate [Function] 12
Description: Truncates real1 towards zero. The integer part is returned as integer, the
remainder is returned as real2.
floor/ [Function] 12
Description: Divides real2 into real1 and truncates the result towards negative infinity. The
integer part of the result is returned as integer, the remainder is returned as real3.
ceiling/ [Function] 12
Description: Divides real2 into real1 and truncates the result towards positive infinity. The
integer part of the result is returned as integer, the remainder is returned as real3.
round/ [Function] 12
Description: Divides real2 into real1 and rounds the result towards the nearest mathematical
integer. The integer part of the result is returned as integer, the remainder is
returned as real3.
truncate/ [Function] 12
Description: Divides real2 into real1 and truncates the result towards zero. The integer part
of the result is returned as integer, the remainder is returned as real3.
modulo [Function] 12
remainder [Function] 12
logior [Function] 12
logxor [Function] 12
logand [Function] 12
lognot [Function] 12
logbit? [Function] 12
Description: Returns true if the indexth bit in integer is a one-bit; otherwise it returns false.
Negative integers are treated as if they were in two’s-complement notation.
ash [Function] 12
ash(8, 1)
⇒ 16
ash(32, -1)
⇒ 16
lcm [Function] 12
gcd [Function] 12
identity [Function] 12
Values: object An instance of <object>; the same object that was passed in as
an argument.
values [Function] 12
Values: the-values Zero or more instances of <object>; the objects that were
passed as arguments.
values(1, 2, 3);
⇒ 1 // first value returned
2 // second value returned
3 // third value returned
Description: Coerces object to type. That is, it returns an instance of type that has the same
contents as object. If object is already an instance of type, it is returned
unchanged. In general, the value returned may or may not be freshly allocated.
Predefined methods allow coercion between integers and characters, between
strings and symbols, and between collection types. No methods are predefined
for other classes. Programs may define additional methods.
as (<symbol>, "foo")
⇒ #"foo"
#"FOO" == as (<symbol>, "foo")
⇒ #t
#"Foo"
⇒ #"foo"
as (<string>, #"Foo")
⇒ "Foo"
Coercing Case 12
Description: Coerces an object to uppercase and returns the resulting new object.
object1 is not modified by this operation.
Values: object An instance of <object>; the same object that was passed in as
an argument.
Description: Coerces an object to uppercase in place and returns the modified object.
object may be modified by this operation, and the result will be == to the object.
Description: Coerces an object to lowercase and returns the resulting new object.
object1 will not be modified by this operation.
Values: object An instance of <object>; the same object that was passed in as
an argument.
Description: Coerces an object to lowercase in place and returns the modified object.
object may be modified by this operation, and the result will be == to the object.
Copying Objects 12
Description: Returns a new object that has the same contents as object1. The contents are
not copied but are the same objects contained in object1.
There is a predefined method for instances of <collection>. For other
classes, the programmer must provide a method.
Collection Operations 12
Note to implementors:
Functions such as map, map-as that return a new collection cannot rely on the
type they instantiate having a valid default for fill:. Therefore when the
size of the result is non-zero these functions should compute the first element
of the result before making the collection, and specify that element as the
fill: value. Otherwise a spurious type error could occur when making the
collection.
Collection Properties 12
Description: Computes the position according to the row-major ordering of array for the
element that is specified by subscripts, and returns the position of that
element.
An error is signaled if the number of subscripts is not equal to the rank of the
array. An error is signaled if any of the subscripts are out of bounds for array.
method for key-test must return the same value (compared with ==) each
time it is called.
Selecting Elements 12
Description: Returns the element associated with key in collection. If no element is associated
with key, then the behavior of element depends on whether it was called with
a default argument: if a default argument was passed, its value is returned;
otherwise, an error is signaled.
All collections are required to implement element.
Description: Alters mutable-collection so that the value associated with key will subsequently
be new-value. If mutable-collection is stretchy, element-setter may also
change its size (for example, by adding new keys with values).
An error is signaled if a program calls element-setter with a key that is not
already a key to collection, unless the collection is stretchy.
Stretchy collections allow element-setter to be called with a key that is not
present in the collection, expanding the collection as necessary to add a new
element in that case. Each concrete subclass of <stretchy-collection>
must provide or inherit a method for element-setter that behaves as
follows when there is not already an element present for the indicated key:
■ If the class is a subclass of <explicit-key-collection>, adds a new
element to the collection with the indicated key.
■ If the class is a subclass of <sequence>, first calls size-setter on the key
+ 1 and the collection to expand the sequence. The key must be a
non-negative integer.
Description: Sets the element of array indicated by indices to the new-value and returns the
new-value.
array is modified by this operation.
An error is signaled if the number of indices is not equal to the rank of the array.
An error is signaled if any of the indices are out of bounds for array. An error is
signaled if the array is limited to hold objects of a particular type and the new
value is not an instance of that type.
first [Function] 12
Description: Returns the first element of the sequence by calling element with the supplied
arguments and the corresponding index.
Note that because element is zero-based, first(seq) is equivalent to
element(seq, 0) and seq[0].
second [Function] 12
Description: Returns the second element of the sequence by calling element with the
supplied arguments and the corresponding index.
third [Function] 12
Description: Returns the third element of the sequence by calling element with the supplied
arguments and the corresponding index.
first-setter [Function] 12
Description: Sets the first element of the mutable-sequence and returns the new-value, by
calling element-setter with the supplied arguments and the
corresponding index.
second-setter [Function] 12
Description: Sets the second element of the mutable-sequence and returns the new-value, by
calling element-setter with the supplied arguments and the
corresponding index.
third-setter [Function] 12
Description: Sets the third element of the mutable-sequence and returns the new-value, by
calling element-setter with the supplied arguments and the
corresponding index.
head [Function] 12
tail [Function] 12
head-setter [Function] 12
Description: Sets the head of pair to contain object and returns object.
pair is modified by this operation.
Example
tail-setter [Function] 12
Description: Sets the tail of pair to contain object and returns object.
pair is modified by this operation.
Arguments: source-sequence
An instance of <sequence>.
new-element
An instance of <object>.
Values: result-sequence
An instance of <sequence>.
Description: Returns a sequence that contains new-element and all the elements of
source-sequence. The result-sequence may or may not be freshly allocated. It may
share structure with a preexisting sequence.
source-sequence is not modified by this operation.
The result-sequence’s size is one greater than the size of source-sequence. The
generic function add doesn’t specify where the new element will be added,
although individual methods may do so.
Arguments: source-sequence
An instance of <sequence>.
new-element An instance of <object>.
Values: result-sequence
An instance of <sequence>.
Description: Returns a sequence that contains new-element and all the elements of
source-sequence. The result-sequence may or may not be freshly allocated. It may
share structure with a preexisting sequence. source-sequence and result-sequence
may or may not be ==.
source-sequence may be modified by this operation.
result-sequence’s size is one greater than the size of source-sequence. The generic
function add! doesn’t specify where the new element will be added, although
individual methods may do so.
Arguments: source-sequence
An instance of <sequence>.
new-element An instance of <object>.
test An instance of <function>. The default is ==.
Values: result-sequence
An instance of <sequence>.
Arguments: source-sequence
An instance of <sequence>.
new-element An instance of <object>.
test An instance of <function>. The default is ==.
Arguments: source-sequence
An instance of <sequence>.
value An instance of <object>.
test An instance of <function>. The default is ==.
count An instance of <integer> or #f. The default is #f.
Values: result-sequence
An instance of <sequence>.
Arguments: source-sequence
An instance of <sequence>.
value An instance of <object>.
test An instance of <function>. The default is ==.
count An instance of <integer> or #f. The default is #f.
Values: result-sequence
An instance of <sequence>.
Values: new-value An instance of <object>. The same object that was passed in
as an argument.
Description: Removes the first element from deque and returns it.
deque is modified by this operation.
Values: new-value An instance of <object>. The same object that was passed in
as an argument.
Description: Removes the last element from deque and returns it.
deque is modified by this operation.
Reordering Elements 12
Returns a sequence with elements in the reverse order of its argument sequence.
Arguments: source-sequence
An instance of <sequence>.
Values: result-sequence
An instance of <sequence>.
Returns a sequence with elements in the reverse order of its argument sequence.
Arguments: source-sequence
An instance of <sequence>.
Values: result-sequence
An instance of <sequence>.
Arguments: source-sequence
An instance of <sequence>.
test An instance of <function>. The default is <.
stable An instance of <object>, treated as a boolean.
Values: result-sequence
An instance of <sequence>.
If stable is supplied and not #f, a possibly slower algorithm will be used that
will leave in their original order any two elements, x and y, such that test(x, y)
and test(y, x) are both false.
Arguments: source-sequence
An instance of <sequence>.
test An instance of <function>. The default is <.
stable An instance of <object>, treated as a boolean.
Values: result-sequence
An instance of <sequence>.
second (in some appropriate sense). If the first argument is greater than or
equal to the second (in the appropriate sense), then the test should return #f.
If stable is supplied and not #f, a possibly slower algorithm will be used that
will leave in their original order any two elements, x and y, such that test(x, y)
and test(y, x) are both false.
define variable *numbers* = vector(3, 1, 4, 1, 5, 9)
*numbers*
⇒ #[3, 1, 4, 1, 5, 9]
sort! (*numbers*)
⇒ #[1, 1, 3, 4, 5, 9]
*numbers*
⇒ {undefined}
Set Operations 12
Description: Returns a new sequence containing only those elements of sequence1 that also
appear in sequence2.
test is used to determine whether an element appears in sequence2. It is always
called with an element of sequence1 as its first argument and an element from
sequence2 as its second argument. The order of elements in the result sequence
is not specified.
new-sequence may or may not share structure with the sequence1 and sequence2.
Arguments: source-sequence
An instance of <sequence>.
test An instance of <function>. The default is ==.
Values: result-sequence
An instance of <sequence>.
Description: Returns a sequence that contains all the unique elements from source-sequence
but no duplicate elements.
test is the function used to determine whether one element is a duplicate of
another. The test argument may be non-commutative; it will always be called
with its arguments in the same order as they appear in source-sequence.
The result-sequence may or may not be freshly allocated. However, the
source-sequence will not be modified by this operation.
Arguments: source-sequence
An instance of <sequence>.
test An instance of <function>. The default is ==.
Values: result-sequence
An instance of <sequence>.
Description: Returns a sequence that contains all the unique elements from source-sequence
but no duplicate elements.
test is the function used to determine whether one element is a duplicate of
another. The test argument may be non-commutative; it will always be called
with its arguments in the same order as they appear in source-sequence.
The result-sequence may or may not be freshly allocated, may or may not share
structure with the source-sequence, and may or may not be == to the
source-sequence. The source-sequence may or may not be modified by the
operation.
Subsequence Operations 12
Values: new-sequence
A freshly allocated instance of <sequence>.
Description: Creates a freshly allocated sequence containing the elements of source between
start and end.
concatenate [Function] 12
Arguments: first-sequence
An instance of <sequence>.
more-sequences
Instances of <sequence>.
Values: result-sequence
An instance of <sequence>.
Description: Returns a sequence containing all the elements of all the sequences, in order.
The result-sequence will be an instance of the type-for-copy value for
first-sequence. It may or may not be freshly allocated. The result-sequence may be
created by calling make on the indicated type, with a size: initialization
argument whose value is the sum of the sizes of the argument sequences. (For
this reason, the type-for-copy value of first-sequence must support the
size: init-keyword.)
new-sequence may share structure with any of the argument sequences, but it is
not guaranteed to do so. The argument sequences will not be modified by this
operation.
concatenate-as [Function] 12
Values: result-sequence
An instance of type, and therefore also an instance of
<sequence>.
Description: Returns a sequence containing all the elements of all the sequences, in order.
The result-sequence will be an instance of type. It may or may not be freshly
allocated.
type must be a subtype of <mutable-sequence> and acceptable as the first
argument to make. size: with a non-negative integer value must be an
acceptable initarg for make of type. The result-sequence may be created by
calling make on type, with a size: initialization argument whose value is the
sum of the sizes of the arguments.
Example
Example
Simple Mapping 12
The following mapping functions (do, map, map-as, map-into, any?,
every?) iterate over a number of source collections. Each time through the
iteration, a function is applied to one element from each of the source
collections. The number of arguments to the function is equal to the number of
source collections.
The functions vary in how they handle the results of each function application.
do [Function] 12
Description: Applies function to corresponding elements of all the collections and returns #f.
If all the collections are sequences, do guarantees that they will be processed in
their natural order.
map [Function] 12
Iterates over one or more collections and collects the results in a freshly
allocated collection.
Description: Creates a freshly allocated collection whose elements are obtained by calling
function on corresponding elements of all the collections. If all the collections are
sequences, processing is performed in the natural order.
map returns a collection whose value is an instance of the type-for-copy
value of collection. The new collection is created by calling make on that type,
with a size: initialization argument whose value is the number of
corresponding elements in the collections.
map (\+,
#(100, 100, 200, 200),
#(1, 2, 3, 4))
⇒ #(101, 102, 203, 204)
map-as [Function] 12
Iterates over one or more collections and collects the results in a freshly
allocated collection of a specified type.
more-collections
Instances of <collection>.
Description: Creates a freshly allocated collection of type type whose elements are obtained
by applying function to corresponding elements of the collection arguments.
type must be acceptable as the first argument to make. size: with a
non-negative integer value must be an acceptable initarg for make of type.
new-collection is created by calling make on type, with a size: initialization
argument whose value is the number of corresponding elements in the
collections. If all the collections are sequences (including new-collection),
processing is done in the natural order.
map-into [Function] 12
Iterates over one or more collections and collects the results in an existing
mutable collection.
Arguments: mutable-collection
An instance of <mutable-collection>.
function An instance of <function>.
collection An instance of <collection>.
more-collections
Instances of <collection>.
Values: mutable-collection
An instance of <mutable-collection>.
any? [Function] 12
Returns the first true value obtained by iterating over one or more collections.
every? [Function] 12
Combines the elements of a collection and a seed value into a single value by
repeatedly applying a binary function.
Description: Returns the result of combining the elements of collection and initial-value
according to function.
If collection is empty, reduce returns initial-value; otherwise, function is applied
to initial-value and the first element of collection to produce a new value. If
more elements remain in the collection, then function is called again, this time
with the value from the previous application and the next element from
collection. This process continues until all elements of collection have been
processed.
function is a binary function used to combine all the elements of collection into a
single value. Processing is always done in the natural order for collection.
Example
Values: result-sequence
An instance of <sequence>.
Values: result-sequence
An instance of <sequence>.
Description: Returns true if collection contains value as determined by test. Otherwise returns
false.
The test function may be non-commutative: it is always called with value as its
first argument and an element from collection as its second argument.
Returns the key in a collection such that the corresponding collection element
satisfies a predicate.
Description: Returns a key value such that (predicate (element collection key)) is true. If no
element in collection satisfies predicate, find-key returns failure.
The skip argument indicates that the first skip matching elements should be
ignored. If skip or fewer elements of collection satisfy predicate, then failure is
returned. If collection is not stable under iteration, then skip is only useful for
finding out whether collection contains at least skip elements which satisfy
predicate; it is not useful for finding a particular element.
flavors
⇒ #(#"vanilla", #"pistachio", #"ginger")
find-key (flavors, has-nuts?)
⇒ 1
flavors[1]
⇒ #"pistachio"
Description: Modifies collection so that it no longer has a key equal to key. Equality is
determined by collection’s key-test function.
The boolean return value will be #t if the key was present and removed, or #f if
the key was not present and hence not removed.
Arguments: mutable-collection
An instance of <mutable-collection>.
predicate An instance of <function>.
new-value-fn
An instance of <function>.
count An instance of <integer> or #f. The default is #f.
Description: Replaces those elements of mutable-collection for which predicate returns true.
The elements are replaced with the value of calling new-value-fn on the existing
element. If count is #f, all of the matching elements are replaced. Otherwise,
no more than count elements are replaced.
mutable-collection may be modified by this operation.
Arguments: mutable-collection
An instance of <collection>.
value An instance of <object>.
start An instance of <integer>.
end An instance of <integer>.
Values: mutable-collection
An instance of <collection>.
Description: Returns eight values used to implement iteration over the collection argument.
Only the collection argument this function was called with may be used as the
collection argument to functions returned by this function. Only the initial-state
object and state objects returned by the next-state and copy-state functions may
be used as the state argument to functions returned by this function. Only the
limit object may be used as the limit argument to the finished-state? function.
forward-iteration-protocol table
⇒ initial-state limit next-state finished-state? current-key current-element
current-element-setter copy-state [G.F. Method] 12
The method for <table> implements the iteration protocol in terms of the
function table-protocol.
Description: Returns eight values used to implement reverse iteration over the collection
argument.
Some collection classes that are stable under iteration support the ability to
iterate in the reverse of the natural order, by providing a method on the generic
function backward-iteration-protocol. The eight values returned by
this function are analogous to the corresponding values returned by
forward-iteration-protocol.
Description: Returns the test-function and hash-function for the <table>. These functions
are in turn used to implement the other collection operations on <table>.
merge-hash-codes [Function] 12
Returns a hash-code created from the merging of two argument hash codes.
Description: Computes a new hash code by merging the argument hash codes in some
implementation dependent way.
id1, id2, and merged-id are all integers. state1, state2, and merged-state are all
hash states. ordered is a boolean and determines whether the algorithm used to
perform the merge is permitted to be order dependent. If false, which is the
default, then the merged result must be independent of the order in which the
argument pairs are provided. If true, then the order of the argument pairs
matters because the algorithm used need not be either commutative or
associative. Providing a true value for ordered is recommended when doing so
will not cause the hash function to violate the second constraint on hash
functions, because it may result in a better distribution of hash ids.
state1 and state2 should be the value of $permanant-hash-state or
hash-states returned from previous calls to merge-hash-codes or
object-hash.
object-hash [Function] 12
Description: Returns a hash-code for object which corresponds to the equivalence predicate
==. It is made available as a tool for writing hash functions in which the object
identity of some component of a key is to be used in computing the hash code.
It returns a hash id (an integer) and associated hash state for the object,
computed in some implementation dependent manner. The values returned by
object-hash when called repeatedly on the same object might not be the
same for each call. If the hash-id value changes then the hash-state value will
also change.
instance? [Function] 12
subtype? [Function] 12
Description: Returns true if type1 is a subtype of type2. Subtype rules are given in “The Type
Protocol” on page 47
object-class [Function] 12
all-superclasses [Function] 12
Description: Returns all the superclasses of class in a sequence. The order of the classes in
the sequence will correspond to the class precedence list of class.
The result sequence should never be destructively modified. Doing so may
cause unpredictable behavior. If class is sealed, an implementation may choose
to signal an error of type <sealed-object-error> rather than returning the
sequence of all superclasses.
direct-superclasses [Function] 12
Description: Returns the direct superclasses of class in a sequence. These are the classes that
were passed as arguments to make or define class when the class was
created. The order of the classes in the sequence is the same as the order in
which they were passed to define class or make when class was created.
The result sequence should never be destructively modified. Doing so may
cause unpredictable behavior. If class is sealed, an implementation may choose
to signal an error of type <sealed-object-error> rather than returning the
direct superclasses.
direct-subclasses [Function] 12
Description: Returns the direct subclasses of class in a sequence. These are the classes that
have class as a direct superclass. The order of the classes in the sequence is not
significant.
The result sequence should never be destructively modified. Doing so may
cause unpredictable behavior. If class is sealed, an implementation may choose
to signal an error of type <sealed-object-error> rather than returning the
direct subclasses.
Functional Operations 12
The following operations are used to create new functions from other functions
or objects. Often the Dylan compiler will have special knowledge of these
operations, to allow for efficient in-line compilation.
compose [Function] 12
Description: When called with just a single argument, compose returns that argument.
When called with two arguments, compose returns a function that applies the
second function to its arguments and then applies the first function to the
(single) result value.
complement [Function] 12
Description: Returns a function that applies predicate to its arguments. If the predicate
returns #f, the complement returns #t; otherwise, the complement returns #f.
For example, odd? could be defined as complement(even?).
disjoin [Function] 12
Description: Returns a single function, termed the disjunction of its argument functions.
The disjunction accepts any number of arguments and operates by applying
the predicates, in order, to the arguments. If any of the predicates returns true,
the remaining predicates (if any) are not applied, and the true result is
returned. Otherwise, all the predicates will be applied, and #f returned.
A disjunction is similar to an | expression of calls to the predicates.
conjoin [Function] 12
Description: Returns a single function, termed the conjunction of its argument functions.
The conjunction accepts any number of arguments and operates by applying
the predicates, in order, to the arguments. If any of the predicates returns #f,
the remaining predicates (if any) are not applied and #f is immediately
returned. Otherwise, all the predicates will be applied, and the result of the last
application is returned.
A conjunction is similar to an & expression of calls to the predicates.
curry [Function] 12
Description: Returns a function that applies function to curried-arguments plus its own
arguments, in that order. For example curry (\>, 6) is a predicate that
returns true for values less than 6; curry (\=, "x") is a predicate that tests
for equality with the string "x"; curry (\+, 1) is an incrementing function;
curry (concatenate, "set-") is a function that concatenates the string
"set-" to any additional sequences it is passed.
rcurry [Function] 12
Description: Returns a function that applies function to curried-arguments plus its own
arguments, with the curried-arguments occuring last.
rcurry (“right” curry) operates just like curry, except it allows the rightmost
arguments of function to be specified in advance, rather than the leftmost
arguments. For example, rcurry (\>, 6) is a predicate that returns true for
values greater than 6.
always [Function] 12
Description: Returns a function that can be called with any number of arguments. The
function ignores its arguments and always returns object.
Function Application 12
apply [Function] 12
Description: Calls function and returns the values which function returns. The argument and
more-arguments supply the arguments to function. All but the last of argument
and more-arguments are passed to function individually. The last of argument and
more-arguments must be a sequence. This sequence is not passed as a single
argument to function. Instead, its elements are taken individually as arguments
to function.
generic-function-methods [Function] 12
Arguments: generic-function
An instance of <generic-function>.
Description: Returns a sequence of all of the methods in generic-function. The order of the
methods in the sequence is not significant. The sequence returned should never
be destructively modified. Doing so may cause unpredictable behavior.
If generic-function is sealed, an implementation may choose not to return a
sequence of methods, but instead signal an error of type
<sealed-object-error>.
add-method [Function] 12
Arguments: generic-function
An instance of <generic-function>.
method An instance of <method>.
generic-function-mandatory-keywords [Function] 12
Arguments: generic-function
An instance of <generic-function>.
function-specializers [Function] 12
Description: Returns a sequence of the specializers for function. The length of the sequence
will equal the number of required arguments of function. The first element of
the sequence will be the specializer of the first argument of function, the second
will be the specializer of the second argument, etc.
The sequence returned should never be destructively modified. Doing so may
cause unpredictable behavior.
function-arguments [Function] 12
Values: required-number
An instance of <integer>.
rest-boolean An instance of <boolean>.
kwd-sequence
Either #f or the symbol #”all” or an instance of
<collection> whose elements are instances of <keyword>.
function-return-values [Function] 12
Values: return-value-types
An instance of <sequence>. The elements of the sequence are
instances of <type>.
rest-return-value
An instance of <type> or #f.
applicable-method? [Function] 12
sorted-applicable-methods [Function] 12
Returns all the methods in a generic function that are applicable to sample
arguments, sorted in order of specificity.
Arguments: generic-function
An instance of <generic-function>.
sample-arguments
Instances of <object>.
Values: sorted-methods
An instance of <sequence>. Elements of the sequence are
instances of <method>.
unsorted-methods
An instance of <sequence>. Elements of the collection are
instances of <method>.
Description: Returns two sequences that, taken together, contain the methods in
generic-function that are applicable to the sample-arguments. sorted-methods
contains methods that are more specific than every method that follows them.
unsorted-methods begins at the first point of ambiguity; it contains the methods
that cannot be sorted.
The sequences returned should never be destructively modified. Doing so may
cause unpredictable behavior.
find-method [Function] 12
Arguments: generic-function
An instance of <generic-function>.
specializers An instance of <sequence>. Elements of the sequence are
instances of <type>.
Description: Returns the method in generic-function that has the specializers in specializers as
its specializers. The specializers must match exactly for a method to be
returned.
If generic-function is sealed, an implementation may choose to signal an error of
type <sealed-object-error> rather than return a value.
remove-method [Function] 12
Arguments: generic-function
An instance of <generic-function>.
method An instance of <method>.
Operations on Conditions 12
Signaling Conditions 12
signal [Function] 12
Signals a condition.
Description: Signals the condition, trying each active dynamic handler, the most recent first.
If all dynamic handlers decline, signal calls default-handler(condition).
If a handler returns, all the values that it returned are returned from signal. If
signal returns when condition’s recovery protocol does not allow returning,
some handler has violated protocol; signal does not check for this error. If
condition is a restart, the caller of signal should always assume that it might
return.
The second form signals a condition of type <simple-warning>.
error [Function] 12
Description: error is similar to signal but never returns; if a handler returns, error
invokes the debugger immediately. error is used to make it clear that a
program does not expect to receive control again after signaling a condition
and might enable the compiler to generate slightly more compact code.
The second form signals a condition of type <simple-error>.
cerror [Function] 12
Description: cerror is the same as error but first establishes a handler for
<simple-restart>, with a format string of restart-description and format
arguments of a sequence containing the arguments.
If the restart handler is invoked, cerror returns #f; otherwise, cerror never
returns. If cerror returns, the program should take the corrective actions
break [Function] 12
Description: Obtains a condition in the same way as signal but then invokes the debugger
immediately without signaling first. break establishes a <simple-restart>
so the debugger can continue execution. This is useful for breakpoints. break
always returns #f. With no arguments, a default message string is used.
check-type [Function] 12
Description: Checks value to ensure that it is an instance of type, and signal an error of type
<type-error> if it is not.
abort [Function] 12
Signature: abort
Arguments: None.
Handling Conditions 12
Description: Engages the interactive user in a dialog and stores the results in slots of restart.
This function is designed to be called from a handler, after making a restart and
before signaling it. The debugger uses restart-query, for example. There is
a default method for <restart> which does nothing.
Description: If the recovery protocol of condition allows returning values, this engages the
program user in a dialog and returns the results as any number of values,
which the handler should return.
Introspection on Conditions 12
do-handlers [Function] 12
Description: Applies function to all dynamically active handlers, the most recently
established first. function receives four arguments: type, test, function, and
init-arguments. The arguments describe a dynamically active handler. All
arguments have dynamic extent and must not be modified. test defaults to a
function that always returns #t. init-arguments will be an empty sequence if it
was not supplied by the handler.
There is a default method for <condition> that returns #f. Programs which
define condition classes whose recovery protocol allows returning values
should ensure that there is an appropriate method for this function defined on
or inherited by the condition class.
condition-format-string [Function] 12
Arguments: simple-condition
An instance of <simple-error>, <simple-warning>, or
<simple-restart>.
Description: Returns the format string that was supplied as an initialization argument when
the simple-condition was created.
condition-format-arguments [Function] 12
Arguments: simple-condition
An instance of <simple-error>, <simple-warning>, or
<simple-restart>.
type-error-value [Function] 12
Description: Returns the value which was not of the expected type, and thereby led to the
type error.
type-error-expected-type [Function] 12
Returns the expected type of the type check that led to the type error.
Description: Returns the expected type of the type check that led to the type error.
Contents
Other Built-In Objects 357
Contents 355
356 Contents
C H A P T E R 1 3
#t [<boolean>] 13
#f [<boolean>] 13
$permanent-hash-state [<object>] 13
#() [<empty-list>] 13
Contents
Overview 361
Definitions 361
Local Declarations 377
Statements 382
Special Operators 397
Contents 359
360 Contents
C H A P T E R 1 4
Overview 14
This chapter contains descriptions of the built-in macros, special definitions,
and special operators defined by Dylan.
The syntax used in this chapter is described in “Manual Notation” on page 6.
Definitions 14
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.
Overview 361
362 Definitions
C H A P T E R 1 4
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>.
Definitions 363
C H A P T E R 1 4
364 Definitions
C H A P T E R 1 4
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 permit the keyword argument strength:.
Definitions 365
C H A P T E R 1 4
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 Inert Domain” on page 136.
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 82.
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.
366 Definitions
C H A P T E R 1 4
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 inert. 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 }
Definitions 367
C H A P T E R 1 4
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
368 Definitions
C H A P T E R 1 4
Defines and names a module, describing the imports and exports of the
module.
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
Definitions 369
C H A P T E R 1 4
370 Definitions
C H A P T E R 1 4
Definitions 371
C H A P T E R 1 4
invert-line,
skew-line
frame-rect,
fill-rect,
erase-rect,
invert-rect;
end module graphics;
graphics
draw-line
erase-line
invert-line
372 Definitions
C H A P T E R 1 4
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
Definitions 373
C H A P T E R 1 4
and the dylan-gx module is that one variable is renamed, and the dylan-gx
module exports the variables which it imports from the dylan module, while
the graphics module does not.
Defines and names a library, describing the imports and exports of the library.
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.
374 Definitions
C H A P T E R 1 4
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 which 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
rexported 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.
n 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.
Definitions 375
C H A P T E R 1 4
Restricts the ways in which a generic function and set of types can be extended,
thereby enabling additional error checking and compiler optimization.
376 Definitions
C H A P T E R 1 4
Arguments: generic-function
variable-namebnf
type expressionbnf
Description: define inert domain seals the specified generic-function over the domain
indicated by the types. For a complete description of the rules governing
define inert domain and the implications of a define inert domain
definition, see “Define Inert Domain” on page 133.
■ 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.
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 being excluded or renamed using
module operations.
Local Declarations 14
Local declarations are used to create bindings or install handlers that are active
for the remainder of the innermost body containing the declaration. Bindings
created by local declarations can be referenced only in the remaining program
text of the body. Handlers installed are active while the execution of the
remainder of the body is active, which includes the time during which any
functions called from the remainder of the body are active.
Creates and initializes new local bindings within the smallest enclosing implicit
body.
Description: let creates local bindings for the variables, and initializes them to the values
returned by init. The bindings are visible for the remainder of the smallest
enclosing implicit body.
The first value returned by the init 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.
Each variable is a variable-name or a variable-name followed by a specializer.
If more than one binding is defined, the variables are enclosed in parentheses
and separated by commas.
let start = 0;
Local variables may be specialized. This ensures that their value will always be
of a given type. An attempt to initialize or assign the variable to a value not of
that type will signal an error of type <type-error>.
Creates new local bindings within the smallest enclosing implicit body and
initializes them to local methods which can be self-recursive and
mutually-recursive.
Macro Call: local { [ method ] name parameter-list [ body ] end [ method ] [ name ] } ,+
Description: local is creates local methods which may be mutually recursive and
self-recursive.
Each name creates a new local binding. The binding is initialized to a new
method specified by the parameter-list and body. In addition to being visible for
the remainder of the smallest enclosing implicit body, the bindings created for
the names are visible to the parameter-lists and bodies of all the methods created
by the local declaration.
The parameter-list is a standard method parameter list. A complete description
of parameter lists is given in “Parameter Lists” on page 82.
The body is an implicit body.
Description: let handler establishes a new condition handler which is in effect for the
duration of the execution of the remainder of the smallest enclosing implicit
body. Unlike the local declarations let and local, let handler does not
create any bindings.
■ The condition describes the conditions for which the handler is applicable.
n The type is the type of the applicable conditions. The handler will be
applicable to conditions that are general instances of type.
n The test-option is a function which is called to further test the applicability
of the handler. When a condition of type type is signaled, the test function
will be called with that condition as an argument. If the test returns true,
the handler is considered applicable to the condition. If the test returns
false, the handler is considered to be inapplicable to the condition. The
default value of this option is a function that always returns true. There
can be at most one test-option.
An example use for this feature is a restart handler for restarting only
from a particular condition object, for example restarting from an
unbound-slot error by setting the slot and retrying the invocation of the
accessor. The <set-and-continue> restart condition will have the
signaled <unbound-slot> condition in a slot, and the handler’s test will
check for it. (These class names are invented for this example and are not
part of the specification.)
n The init-option is a sequence of alternating keywords and objects which
can be used as initialization arguments to construct a condition to which
the handler is applicable. It defaults to an empty sequence. For example,
if the handler is a restart handler, a program could use the initialization
arguments to construct a restart. (The program would retrieve the
keyword/value pairs by calling do-handler.) There can be at most one
init-option.
■ The handler is function called to handle a condition that matches type and
passes test-option. The function should accept two arguments. The first
argument will be the condition being signaled, and the second argument
will be a next-handler function. The handler handles the condition by
taking a non-local exit, returning values according to the condition’s
recovery protocol, or tail-recursively calling signal of a restart. The
function can decline to handle the condition by tail-recursively calling the
next-handler function with no arguments.
test-option and handler are distinct so that handler applicability can be tested
without actually handling (which might take a non-local exit). One use for this
is constructing a list of available restart handlers.
There is no “condition wall,” i.e., when executing handler the set of available
handlers is not reset to the handlers that were in effect when the let handler
was entered.
Implementations are encouraged to implement let handler in a way that
optimizes establishing a handler for both speed and space, even if that
increases the cost of signaling. The assumption is that most of the time a
handler will never be used, because the exception it is looking for will never
occur.
type, handler, test-option, and init-option are executed before execution of the rest
of the enclosing body begins.
Statements 14
Statements are used to implement a variety of program constructs.
Many statements include an optional implicit body, which may contain one or
more constintuents separated by semicolons. When an implicit body is
executed, the expressions in the implicit body are executed in order (left to
right). The values of the implicit body are the values of the last expression. If
the optional implicit body is not present or contains no expressions, the return
value is #f.
382 Statements
C H A P T E R 1 4
Conditionals 14
if [Statement] 14
Executes an implicit body if the value of a test is true or an alternate if the test
is false.
Description: if executes one or more expressions, executing and returning the values of a
body following the first test which returns true.
test is the first expression to be executed. If its value is true, if executes and
returns the values of the consequent. If the value of test is false, if proceeds
with the optional elseif-tests and alternate.
Statements 383
C H A P T E R 1 4
First the elseif clauses are tried in order. The first elseif-test is executed. If its
value is true, the corresponding elseif-consequent is executed and its values are
returned as the value of the if statement. If its value is false, the next elseif-test
is tried. This continues until a true elseif-test is found, or until there are no more
elseif clauses.
If the test and all the elseif-tests are false, the alternate is executed and its values
are returned as the value of the if statement. If there is no alternate, the if
statement returns #f.
if ( x < 0 )
- x;
end if;
if ( heads?(flip(coin)) )
start(black);
else
start(white);
end if
if (player1.money <= 0)
end-game(player1)
elseif (player2.money <= 0)
end-game(player2)
else
move(player1);
move(player2);
end if
if ( camel.humps = 1 )
"dromedary"
elseif ( camel.humps = 2 )
"bactrian"
else
"not a camel"
end if;
384 Statements
C H A P T E R 1 4
unless [Statement] 14
Description: unless executes test. If the value of test is false, then the body is executed and
its values are returned by unless. If the value of test is true, the body is not
executed and unless returns #f.
If there are no expressions in the body, then #f is returned.
unless(detect-gas? (nose))
light(match)
end unless
case [Statement] 14
Executes a number of tests until one is true, and then executes an implicit body
associated with the true test.
Statements 385
C H A P T E R 1 4
Description: case executes the test in order, until it reaches a test which returns true. When
it reaches a test which returns true, it executes the corresponding consequent
and returns its values. Subsequent tests are not executed. If the corresponding
consequent is empty, the first value of the successful test is returned.
As a special case, the name otherwise may appear as a test. This test always
succeeds if there is no preceding successful test.
If no test is true, then case returns #f.
case
player1.money <= 0
=> end-game(player1);
player2.money <= 0
=> end-game(player2);
otherwise
=> move(player1);
move(player2);
end case;
select [Statement] 14
386 Statements
C H A P T E R 1 4
Description: select generates a target object and then compares it to a series of potential
matches, in order. If it finds a match, it executes the corresponding consequent
and returns the values of the consequent. If no match is found, an error is
signaled.
The target is executed to produce the match object.
The test, if supplied, is a function used to compare the target object to the
potential matches. The default test is ==.
One at a time, each match is executed and its value compared to target, in order.
If a match is found, the corresponding consequent is executed and its values are
returned. If the corresponding consequent is empty, #f is returned.
Once a match is found, subsequent matches and the corresponding bodies are
not executed.
As a special case, the name otherwise may appear instead of a matches. This
will be considered a match if no other match is found.
If there is no matching clause, an error is signaled. Because an otherwise
clause matches when no other clause matches, a select form that includes an
otherwise clause will never signal an error for failure to match.
Since testing stops when the first match is found, it is irrelevant whether the
test function would also have returned true if called on later matches of the
same clause or on matches of later clauses.
select ( career-choice(student) )
art:, music:, drama:
=> "Don’t quit your day job";
literature:, history:, linguistics:
=> "That really is fascinating";
science:, math:, engineering:
=> "Say, can you fix my VCR?";
otherwise => "I wish you luck";
end select;
Statements 387
C H A P T E R 1 4
Iteration Constructs 14
while [Statement] 14
Values: #f
Values: #f
388 Statements
C H A P T E R 1 4
Each pass through the loop begins by executing test. If test returns false, the
expressions in the body are executed and the looping continues. If test returns
true, the loop terminates and until returns #f.
for [Statement] 14
Performs general iteration over a body, updating bindings and performing end
tests on each iteration.
Statements 389
C H A P T E R 1 4
increment expressionbnf
Description: for iterates over loop-body, creating and updating iteration bindings on each
iteration according to the for-clauses. Iteration ends when one of the for-clauses
is exhausted, or when the optional end-test is satisfied.
Each for-clause controls one iteration binding. The optional end-test does not
control any iteration bindings.
There are three kinds of for-clauses: explicit-step-clauses, collection-clauses, and
numeric-clauses: An explicit-step-clause creates bindings for the results of
executing an expression. A collection-clause creates bindings for successive
elements of a collection. A numeric-clause creates bindings for a series of
numbers.
Execution of a for statement proceeds through the following steps:
1. Execute the expressions that are executed just once, in left to right order as
they appear in the for statement. These expressions include the types of all
the bindings, and the expressions init-value, collection, start, bound, and
increment. If the value of collection is not a collection, an error is signaled.
The default value for increment is 1.
2. Create the iteration bindings of explicit step and numeric clauses.
n For each explicit step clause, create the binding for the value of init-value.
If the binding is typed and the value is not of the specified type, signal an
error.
n For each numeric clause, create the binding for the value of start. If the
binding is typed and the value is not of the specified type, signal an error.
3. Check numeric and collection clauses for exhaustion. If a clause is
exhausted, go to step 9.
n A collection clause is exhausted if its collection has no next element.
n A numeric clause is exhausted if a bound is supplied and the value of the
clause is no longer in bounds. If above is specified, the clause will be in
bounds as long as the value is greater than the bounds. If below is
specified, the clause will be in bounds as long as the value is less than the
bounds. If to is specified with a positive or zero increment, the clause will
be in bounds as long as it is less than or equal to the bounds. If to is
390 Statements
C H A P T E R 1 4
Statements 391
C H A P T E R 1 4
plot (i,j);
end for;
end for;
begin [Statement] 14
Description: Begin executes the expressions in a body, in order. The values of the last
expression are returned. If there are no expressions in the body, #f is returned.
block [Statement] 14
392 Statements
C H A P T E R 1 4
[ cleanup [ cleanup-clause ] ]
{ exception exception-clause }*
end [ block ]
Description: block executes the expressions in the block-body in order, and then the executes
the optional afterwards-clause and cleanup-clause. Unless there is a non-local exit,
block returns the values of the block-body, or #f if there is no block-body.
If exit-variable is provided, it is bound to an exit procedure (an object of type
<function>) which is valid during the execution of the block body and the
clauses. At any point in time before the last clause returns, the exit procedure
can be called. Calling the exit procedure has the effect of immediately
terminating the execution of the block, and returning as values the arguments
to the exit procedure.
The body of the afterwards-clause, if provided, is executed after the block-body.
The values produced by the afterwards-clause are ignored.
The body of the cleanup-clause, if provided, is executed after the block-body and
afterwards-clause. Its values are also ignored. The cleanup clause differs from
the afterwards clause in that its body is guaranteed to be executed, even if the
execution of the block is interrupted by a non-local exit. There is no such
guarantee for the afterwards clauses.
Statements 393
C H A P T E R 1 4
For example, the following code fragment ensures that files are closed even in
the case of an error causing a non-local exit from the block body:
block (return)
open-files();
if (something-wrong)
return("didn't work");
end if;
compute-with-files()
cleanup
close-files();
end block
block (return)
open-files();
compute-with-files()
exception (<error>)
"didn't work")
cleanup
close-files();
end block
394 Statements
C H A P T E R 1 4
Statements 395
C H A P T E R 1 4
method [Statement] 14
Description: method creates and returns a method specified by the parameter-list and body.
For a complete description of methods, see “Methods” on page 78.
396 Statements
C H A P T E R 1 4
Special Operators 14
Special operators provide syntax for assignment and for conditional execution.
Assignment 14
:= [Special Operator] 14
Assignment to a binding 14
If place is a binding name, then new-value is stored in the binding. It is an error
if there is no binding corresponding to place. (:= cannot be used to create
bindings, only to change their values.) An error is also signaled if place is a
binding specialized to a type and the new-value is not of that type.
*top-view*.subviews := generate-subviews()
subviews(*top-view*) := generate-subviews()
subviews-setter(generate-subviews(), *top-view*)
expressions will return the value of the call to generate-subviews while the
last will return the value of the call to subviews-setter.)
name(arg1,…argn ) := new-value
begin
let temp = new-value;
name-setter(temp, arg1,…argn );
temp
end
foo[2] := "quux"
element (foo, 2) := "quux"
element-setter ("quux", foo, 2).
Conditional Execution 14
| [Special Operator] 14
Description: | (logical or) executes one. If the first value of one is true, that value is
returned. Otherwise another is executed and its values are returned.
Executes a second operand and returns its values if the value of the first
operand is true.
Description: & (logical and) executes one. If the first value returned by one is false, #f is
returned and another is not executed. Otherwise, another is executed and its
values are returned.
Figure A-0
Listing A-0 BNF A
Table A-0
General Notes A
Dylan syntax can be parsed with an LALR(1) grammar.
This appendix uses some special notation to make the presentation of the
grammar more readable.
■ The opt suffix means that the preceding item is optional.
■ A trailing ellipsis (...) is used in two different ways to signal possible
repetition.
n If there is only one item on the line preceding the ellipsis, the item may
appear one or more times.
n If more than one item precedes the ellipsis, the last of these items is
designated a separator; the rest may appear one or more times, with the
separator appearing after each occurrence but the last. (When only one
item appears, the separator does not appear.)
■ Identifiers for grammar rules are written with uppercase letters when the
identifier is used in the phrase grammar but defined in the lexical grammar.
■ The grammar does not use distinct identifiers for grammar rules that differ
only in alphabetic case.
Lexical Notes A
In the lexical grammar, the various elements that come together to form a
single token on the right-hand sides of rules must not be separated by
white-space, so that the end result will be a single token. This is in contrast to
the phrase grammar, where each element is already a complete token or a
series of complete tokens.
Arbitrary white-space is permitted between tokens, but it is required only as
necessary to separate tokens that might otherwise blend together.
401
BNF
Case is not significant except within character and string literals. The
grammars do not reflect this, using one case or the other, but it is still true.
Lexical Grammar A
Comments A
comment:
// …the rest of the line
/* …everything even across lines… */
Tokens A
TOKEN:
NAME
SYMBOL
NUMBER
CHARACTER-LITERAL
STRING
UNARY-OPERATOR
BINARY-OPERATOR
punctuation
#-word
punctuation:
one of ( ) , . ; [ ] { } :: - = == =>
one of #( #[ ## ? ?? ?= ...
#-word:
one of #t #f #next #rest #key #all-keys #include
Reserved Words A
reserved-word:
core-word
BNF
BEGIN-WORD
FUNCTION-WORD
DEFINE-BODY-WORD
DEFINE-LIST-WORD
core-word:
one of define end handler let local macro otherwise
The following reserved words are exported by the Dylan module:
BEGIN-WORD:
one of begin block case for if method
one of select unless until while
FUNCTION-WORD:
(none)
DEFINE-BODY-WORD:
one of class library method module
DEFINE-LIST-WORD:
one of constant variable
CONSTRAINED-NAME:
NAME : word
NAME : BINARY-OPERATOR
: word
BNF
operator-name:
\ unary-function-operator
\ binary-function-operator
SYMBOL:
word:
# STRING
word:
leading-alphabetic
leading-numeric alphabetic-character leading-alphabetic
leading-graphic leading-alphabetic
leading-alphabetic:
alphabetic-character
leading-alphabetic any-character
leading-numeric:
numeric-character
leading-numeric any-character
leading-graphic:
graphic-character
leading-graphic any-character
any-character:
alphabetic-character
numeric-character
graphic-character
special-character
alphabetic-character:
one of a b c d e f g h i j k l m n o p q r s t u v w x y z
numeric-character:
one of 0 1 2 3 4 5 6 7 8 9
graphic-character:
one of ! & * < > | ^ $ % @ _
special-character:
one of - + ~ ? / =
BNF
Operators A
UNARY-OPERATOR:
unary-function-operator
BINARY-OPERATOR:
binary-function-operator
special-operator
unary-function-operator:
one of - ~
binary-function-operator:
one of + - * / ^ = == ~= ~== < <= > >=
special-operator:
one of & | :=
BNF
Numbers A
NUMBER:
integer
ratio
floating-point
integer:
binary-integer
octal-integer
signopt decimal-integer
hex-integer
binary-integer:
#b binary-digit
binary-integer binary-digit
octal-integer:
#o octal-digit
octal-integer octal-digit
decimal-integer:
decimal-digit
decimal-integer decimal-digit
hex-integer:
#x hex-digit
hex-integer hex-digit
hex-digits:
hex-digit …
binary-digit:
one of 0 1
octal-digit:
one of 0 1 2 3 4 5 6 7
decimal-digit:
one of 0 1 2 3 4 5 6 7 8 9
hex-digit:
one of 0 1 2 3 4 5 6 7 8 9 A B C D E F
BNF
ratio:
signopt decimal-integer / decimal-integer
floating-point:
signopt decimal-integeropt . decimal-integer exponentopt
signopt decimal-integer . decimal-integeropt exponentopt
signopt decimal-integer exponent
exponent:
E signopt decimal-integer
sign:
one of + -
Phrase Grammar A
Program Structure A
source-record:
bodyopt
body:
constituents ;opt
constituents:
constituent ; …
constituent:
definition
local-declaration
expression
macro:
definition-macro-call
statement
function-macro-call
BNF
Property Lists A
comma-property-list:
, property-list
property-list:
property , …
property:
SYMBOL value
value:
basic-fragment
Fragments A
body-fragment:
non-statement-body-fragment
statement non-statement-body-fragmentopt
list-fragment:
non-statement-list-fragment
statement non-statement-list-fragmentopt
basic-fragment:
non-statement-basic-fragment
statement non-statement-basic-fragmentopt
non-statement-body-fragment:
definition semicolon-fragmentopt
local-declaration semicolon-fragmentopt
simple-fragment body-fragmentopt
, body-fragmentopt
; body-fragmentopt
semicolon-fragment:
; body-fragmentopt
non-statement-list-fragment:
simple-fragment list-fragmentopt
, list-fragmentopt
BNF
non-statement-basic-fragment:
simple-fragment basic-fragmentopt
simple-fragment:
variable-name
constant-fragment
BINARY-OPERATOR
UNARY-OPERATOR
bracketed-fragment
function-macro-call
#-word
one of . :: => ? ?? ?= ... ## otherwise
bracketed-fragment:
( body-fragmentopt )
[ body-fragmentopt ]
{ body-fragmentopt }
constant-fragment:
NUMBER
CHARACTER-LITERAL
STRING
SYMBOL
#( constants . constant )
#( constantsopt )
#[ constantsopt ]
Definitions A
definition:
definition-macro-call
define macro macro-definition
definition-macro-call:
define modifiersopt DEFINE-BODY-WORD body-fragmentopt definition-tail
define modifiersopt DEFINE-LIST-WORD list-fragmentopt
modifier:
UNRESERVED-NAME
modifiers:
modifier …
BNF
definition-tail:
end DEFINE-BODY-WORDopt NAMEopt
Local Declarations A
local-declaration:
let bindings
let handler condition = handler
local local-methods
condition:
type
( type comma-property-listopt )
handler:
expression
local-methods:
methodopt method-definition , …
bindings:
variable = expression
( variable-list ) = expression
variable-list:
variables
variables , #rest variable-name
#rest variable-name
variables:
variable , …
variable:
variable-name
variable-name :: type
variable-name:
ORDINARY-NAME
type:
operand
BNF
Expressions A
expressions:
expression , …
expression:
binary-operand BINARY-OPERATOR …
binary-operand:
SYMBOL
UNARY-OPERATORopt operand
operand:
operand ( argumentsopt )
operand [ arguments ]
operand . variable-name
function-macro-call
leaf
arguments:
SYMBOLopt expression , …
function-macro-call:
FUNCTION-WORD ( body-fragmentopt )
FUNCTION-WORD ( body-fragmentopt ) := expression
leaf:
literal
variable-name
( expression )
statement
literal:
NUMBER
CHARACTER-LITERAL
string-literal
#t
#f
#( constants . constant )
#( constantsopt )
#[ constantsopt ]
string-literal:
STRING …
BNF
constants:
constant , …
constant:
literal
SYMBOL
Statements A
statement:
BEGIN-WORD body-fragmentopt end-clause
end-clause:
end BEGIN-WORDopt
case-body:
cases ;opt
cases:
case-label constituentsopt ; …
case-label:
expressions =>
( expressions ) =>
otherwise =>opt
Methods A
method-definition:
variable-name parameter-list bodyopt end methodopt variable-nameopt
parameter-list :
( parametersopt ) ;opt
( parametersopt ) => variable ;
( parametersopt ) => ( values-listopt ) ;opt
parameters:
required-parameters
required-parameters , next-rest-key-parameter-list
next-rest-key-parameter-list
BNF
next-rest-key-parameter-list:
#next variable-name
#next variable-name , rest-key-parameter-list
rest-key-parameter-list
rest-key-parameter-list:
#rest variable-name
#rest variable-name , key-parameter-list
key-parameter-list
key-parameter-list:
#key keyword-parametersopt
#key keyword-parametersopt , #all-keys
#all-keys
required-parameters:
required-parameter , …
required-parameter:
variable
variable-name == expression
keyword-parameters:
keyword-parameter , …
keyword-parameter:
SYMBOLopt variable defaultopt
default:
= expression
values-list:
variables
variables , #rest variable
#rest variable
Macro Definitions A
macro-definition:
NAME main-rule-set auxiliary-rule-setsopt end macroopt NAMEopt
main-rule-set:
body-style-definition-rule ...
list-style-definition-rule ...
BNF
statement-rule ...
function-rule ...
body-style-definition-rule :
{ define definition-headopt NAME patternopt ;opt end } => rhs
list-style-definition-rule :
{ define definition-headopt NAME patternopt } => rhs
rhs:
{ templateopt } ;opt
definition-head :
modifier-pattern ...
modifier-pattern:
modifier
pattern-variable
statement-rule:
{ NAME patternopt ;opt end } => rhs
function-rule:
{ NAME ( patternopt ) } => rhs
Patterns A
pattern:
pattern-list ; ...
pattern-list:
pattern-sequence
property-list-pattern
pattern-sequence , pattern-list
pattern-sequence:
simple-pattern ...
simple-pattern:
NAME
=>
bracketed-pattern
binding-pattern
pattern-variable
BNF
bracketed-pattern:
( patternopt )
[ patternopt ]
{ patternopt }
binding-pattern:
pattern-variable :: pattern-variable
pattern-variable = pattern-variable
pattern-variable :: pattern-variable = pattern-variable
pattern-variable:
? NAME
? CONSTRAINED-NAME
...
property-list-pattern:
#rest pattern-variable
#key pattern-keywordsopt
#rest pattern-variable , #key pattern-keywordsopt
pattern-keywords:
#all-keys
pattern-keyword
pattern-keyword , pattern-keywords
pattern-keyword:
? NAME defaultopt
? CONSTRAINED-NAME defaultopt
?? NAME defaultopt
?? CONSTRAINED-NAME defaultopt
Templates A
template:
template-element ...
template-element:
NAME
SYMBOL
NUMBER
CHARACTER-LITERAL
STRING
UNARY-OPERATOR
BNF
separator
#-word
one of . :: =>
( templateopt )
[ templateopt ]
{ templateopt }
#( templateopt )
#[ templateopt ]
substitution
separator:
one of ; ,
BINARY-OPERATOR
substitution:
name-prefixopt ? name-string-or-symbol name-suffixopt
?? NAME separatoropt ...
...
?= NAME
name-prefix:
STRING ##
name-suffix:
## STRING
name-string-or-symbol:
NAME
STRING
SYMBOL
auxiliary-rule-sets:
auxiliary-rule-set ...
auxiliary-rule-set:
SYMBOL auxiliary-rules
auxiliary-rules:
auxiliary-rule ...
auxiliary-rule:
{ patternopt } => rhs
BNF
BNF
419
420
G L O S S A RY
421
G L O S S A RY
422
G L O S S A RY
423
G L O S S A RY
and computes its values by selecting and values, a hash id and a hash state, which
calling an appropriate method based on the together represent the hash code. See also
types of the arguments. equivalence predicate.
general instance hash id
(of a type) An object that is either a direct An integer encoding of an object.
instance or indirect instance of the type.
hash table
general superclass A table.
(of a class) A class that is either a direct
hash state
superclass or indirect superclass of the
An object of implementation-dependent
class.
type which is associated with a particular
generic function hash id and can be used by the
A function consisting of a family of implementation to determine whether the
methods with a common calling protocol. hash id has been invalidated.
A generic function computes its value by
identical
selecting and calling an appropriate method
(of two objects) Computationally
based on the types of the arguments. See
equivalent. That is, there is no way for any
also method dispatch.
portable Dylan program to distinguish
generic function dispatch them; they are the same under the
See method dispatch. equivalence predicate ==.
get immutable
(the value of a slot) To retrieve the value of Not capable of being modified after it is
the slot. created. It is an error to attempt to modify
an immutable object, though Dylan
getter
implementations are not required to detect
A function that is applied to an object and
this error. The opposite of immutable is
returns the value of one of the object’s slots.
mutable.
handler
implicit definition
A function that is used to respond to a
A definition created by define method
signaled condition.
or by the slot specifications of define
hash code class.
A conceptual object consisting of a hash id
implicitly defined
and its associated hash state.
1. (of a generic function) Created by an
hash function implicit definition rather than by define
A function, associated with a table, that generic. 2. (of a method) Created by a
computes hash code. All hash functions slot specification in a define class
have one argument, a key, and return two definition, rather than by define method.
424
G L O S S A RY
425
G L O S S A RY
426
G L O S S A RY
427
G L O S S A RY
428
G L O S S A RY
429
G L O S S A RY
430
Index
431
A ceiling 267
ceiling/ 268
abs 271 character literal 18
abstract class 50 choose 321
accept all keyword arguments 84 choose-by 322
accept a variable number of arguments 85 class precedence list 52
accept keyword arguments 84 closed over 81
accessible bindings 27 closure 81
add 296 code body 21
add! 297 collection alignment 119
add-new 298 collection keys 115
add-new! 299 comment 16
all-superclasses 332 complement 335
alphabetic character 17 compose 334
altering a collection 117 concatenate 311
always 338 concatenate-as 312
ambiguous methods 93 concrete class 50
any? 318 condition 103
apply 339 condition handler establishing 13
aref 289 congruent parameter lists 91
aref-setter 289 conjoin 336
as 275 constant 10
ash 273 constituent 11
as-lowercase 278 copy-sequence 311
as-lowercase! 278 curry 336
as-uppercase 277
as-uppercase! 277
D
B defaulted initialization arguments 63
define class 366
backward-iteration-protocol 328 define constant 363
base type 48 define generic 364
binary operator call 14 define inert domain 376
binding 10 define library 374
body 11 define macro 377
built-in defining macro 11 define method 365
built-in statement macro 15 define module 369
define variable 362
definition 11
delimited comment 16
C destructively modify 118
dimension 285
case 385
432
I N D E X
G
E gcd 274
general subclass 51
element 286 general superclass 50
element reference 15 getter 24
elements 115 getter method 56
element-setter 287 graphic character 17
element type 122
empty? 281
equivalence class 120
equivalence predicate 120 H
equivalent 48
equivalent types 48 handler 103
even? 262 hash codes 121
every? 319 hash function 121
exit 103, 106 hash id 121
explicit definition 27 hash state 121
explicit key collection 115 head 294
explicitly known 131 head-setter 295
exported bindings 27 hygienic 159
expression 13
I
F identity 274
file header 21 if 383
fill! 325 implicit definition 27
find-key 323 imported bindings 27
first 290 indirect subclass 51
first-setter 291 init expression 58
floor 266 init function 58
floor/ 268 initialization argument 59
for 389 initialization protocol 50
433
I N D E X
434
I N D E X
O remove! 300
remove-duplicates 309
object-class 332 remove-duplicates! 310
object-hash 331 remove-key! 324
odd? 262 replace-elements! 324
open class 50 replace-subsequence! 313
operand 13 require a fixed number of arguments 84
operator 18 required parameters 83
outside stack 105 required value declaration 89
owned module binding 27 reserved word 14
restarting 109
rest parameters 83
rest value declaration 89
P return type declarations 83
reverse 303
pair 249 reverse! 304
parameter list 16, 77 round 267
parenthesized expression 15 round/ 269
permit keywords 85 row-major-index 284
pop 302
pop-last 303
positive? 263
precede in a class precedence list 52 S
primary class 50
program 9 sealed class 50
proper subtype 48 sealing 131
pseudosubtype 48 sealing directives 131
punctuation 19 second 290
push 302 second-setter 292
push-last 302 select 386
sequence 115
setter 24
setter method 56
R shallow-copy 279
signaler 103
range 250 signaling unit 105
rank 283 single-line comment 16
rcurry 337 singleton 250
recognize keywords 85 singleton specializers 87
recovery 103, 106 size 281
recovery protocol 110 size-setter 282
reduce 320 slot-initialized? 248
reduce1 321 slot reference 15
remainder 270 slots 50
remove 300
435
I N D E X
sort 305 V
sort! 306
source record 9 values 275
special definition 12 value type 89
specialize 83, 86 variable 10
specialized 10 vector 254
stable under iteration 116 visibly modified 121
statement 15
statement macro 15
string literal 18
subsequence-position 314 W
subtype? 332
supplied initialization arguments 63 while 388
symbol literal 18 whitespace 16
T Z
U
unary operator call 14
uninstantiable class 50
union 308
unique string 18
unless 385
unstable under iteration 116
until 388
user-defined defining macro 11
user-defined statement macro 15
using a module 27
436
I N D E X
437
T H E A P P L E P U B L I S H I N G S Y S T E M
This Apple manual was written, edited, Zacharias. Past members include Stoney
and composed on a desktop publishing Ballard, Rick Fleischman, Alice Hartley,
system using Apple Macintosh Mike Kahl, Robyn Kozierok, Larisa
computers and FrameMaker software. Matejic, Neil Mayle, Richard Mlynarik,
Line art was created using Robert Muller, Ike Nassi, Tom Parmenter,
Adobe Illustrator and Jeff Piazza, Mark Preece, David
Adobe Photoshop . Rosenfeld, Orca Starbuck and Oliver
Steele. A great deal of language design
Text type is Palatino and display type is
work was done by the Dylan Partners.
Helvetica. Bullets are ITC Zapf
Contributing members of the Gwydion
Dingbats. Some elements, such as
group include Bill Chiles, Scott E.
program listings, are set in Apple Courier.
Fahlman, Paul Gleichauf, Nick Kramer,
William Lott, Rob MacLachlan and
WRITER Robert Stockton. Contributing members
Andrew Shalit, with contributions by of the Harlequin Dylan team include
Orca Starbuck and David Moon. Jonathan Bachrach, Roman
Budzianowski, Paul Haahr, Sonya Keene,
ILLUSTRATOR Robert Mathews, Scott McKay, Tim
Steve Strassmann McNerney, Peter Norvig, Keith Playford,
PRODUCTION EDITOR Toby Weinberg and P. Tucker Withington.
Lorraine Findlay Among the independent Dylan Partners
who contributed are Jim Allard, Patrick
Special thanks to Kim Barrett for his
C. Beard, Mark C. Chu-Carroll, Mutsumi
timely commentary on language design
Komuro, Jonathan Sobel, Joseph N.
questions and wording, to Paul Haahr,
Wilson and Paul R. Wilson. Important
David Moon, and Keith Playford for their
feedback on the language design was
last-minute heroic contributions on a
provided by our ever-patient early users,
number of difficult design issues, to
including Fritz Anderson, Gary Beaver,
Sonya Keene for her work on producing
Edward Cessna, Geoffrey Clements,
an HTML version of this document, and
Enrico Colombini, Donn Denman, Ken
to James Joaquin for coming up with a
Dickey, Mikel Evins, Mark Gavin, James
great language name.
C. Grandy, Wayne Johnson, Scott Joy, Bo
Heartfelt acknowledgments are due to Klintberg, Gabriel Lawrence, Ted
the many people who have contributed Lowery, Matthew MacLaurin,
to the design and validation of Dylan Claes-Fredrik Mannby, Stephen
over the years. The current Apple Dylan McConnell, Nick Nallick, Carl Nelson,
team consists of Kim Barrett, Rick Bryan, Steve Palmen, Paul R. Potts, Mike
Glenn Burke, Bob Cassels, John Rossetti, Larry Tesler and Andrew
Hotchkiss, Jeremy Jones, Phil Kania, Ross Wason. Additional thanks are due to
Knights, Mike Lockwood, Robin Mair, Dave Nagel and Apple Computer for
Dave Moon, Paige Parsons, Kálmán Réti, many years of generous funding.
Carl Schwarcz, Andrew Shalit, David Without the help of these and many
Sotkowitz, Bill St. Clair, Steve other hands, Dylan could not have been
Strassmann, Derek White and Gail created.