Programming Language ISLISP

ISLISP Working Draft 23.0

This document was created Thu 17-Mar-2007 00:10am JST.

Permission to copy all or part of the material in this document, ISLISP Working Draft 23.0, without fee is granted provided that either it is reproduced without modification, or else the portion to be copied no longer identifies itself (through its title or any running headers) as ISLISP Working Draft 23.0.

The textual material that makes up this document, excluding the cover and any running headers that establish the identity of the document itself as ISLISP Working Draft 23.0, is expressly dedicated to the Public Domain, from which individual, copyrighted works (including any resulting ISO standard) may be non-exclusively derived without fee or other restriction.

Yuji Minejima (yuji@minejima.jp) is in charge of this HTML version. (2017 Jul.)

Acknowledgment: Atsushi Saito did the first tagging of HTML version. (2017 Jul.)

ChangeLog: Masaya Taniguchi added sidebar. (2017/07/30)

Introduction

The programming language ISLISP is a member of the LISP family.

The following factors inﬂuenced the establishment of design goals for ISLISP:

A desire of the international LISP community to standardize on those features of LISP upon which there is widespread agreement. The existence of the incompatible dialects COMMON-LISP, EULISP, LE-LISP, and SCHEME (mentioned in alphabetical order). A desire to affirm LISP as an industrial language.

This led to the following design goals for ISLISP:

ISLISP shall be compatible with existing LISP dialects where feasible. ISLISP shall have as a primary goal to provide basic functionality. ISLISP shall be object-oriented. ISLISP shall be designed with extensibility in mind. ISLISP shall give priority to industrial needs over academic needs. ISLISP shall promote efficient implementations and applications.

Programming Language ISLISP

Scope

This document specifies syntax and semantics of the computer programming language ISLISP by specifying requirements for a conforming ISLISP processor and a conforming ISLISP text.

This document does not specify:

the size or complexity of an ISLISP text that exceeds the capacity of any specific data processing system or the capacity of a particular processor, nor the actions to be taken when the corresponding limits are exceeded;

the minimal requirements of a data processing system that is capable of supporting an implementation of a processor for ISLISP;

the method of preparation of an ISLISP text for execution and the method of activation of this ISLISP text, prepared for execution;

the typographical presentation of an ISLISP text published for human reading.

extensions that might or might not be provided by the implementation.

Normative references

The following referenced documents are indispensable for the application of this document. For dated references, only the edition cited applies. For undated references, the latest edition of the referenced document (including any amendments) applies.

ISO/IEC TR 10034:1990, Guidelines for the preparation of conformity clauses in programming language standards.

IEEE standard 754-1985. Standard for binary floating point arithmetic.

Compliance of ISLisp processors and text

An ISLISP processor complying with the requirements of this document shall

accept and implement all features of ISLISP specified in this document.

reject any text that contains any textual usage which this document explicitly defines to be a violation (see §9).

be accompanied by a document that provides the definitions of all implementation-defined features.

be accompanied by a document that separately describes any features accepted by the processor that are not specified in this document; these extensions shall be described as being extensions to ISLISP as specified by ISLISP Working Draft 23.0.

A complying ISLISP text shall not rely on implementation-dependent features. However, a complying ISLISP text may rely on implementation-defined features required by this document.

A complying ISLISP text shall not attempt to create a lexical variable binding for any named constant defined in this document. It is a violation if any such attempt is made.

Terms and definitions

For the purposes of this document, the following terms and definitions apply.

abstract class

class that by definition has no direct instances

activation

computation of a function

Note: Every activation has an activation point, an activation period, and an activation end. The activator, which is a function application form prepared for execution, starts the activation at the activation point.

accessor

association of a reader and a writer for a slot of an instance

argument position

occurrence of a text unit as an element in a form excluding the first one

binding

concept that has both a syntactic and a semantic aspect, where

syntactically, binding describes the relation between an identifier and a binding ISLISP form, and

describes the relation between an identifier and a binding ISLISP form, and semantically, binding describes the relation between a variable, its denoting identifier, and an object (or, the relation between a variable and a location)

Note 1: The property of being bound can be checked textually by relating defining and applied identifier occurrences.

Note 2: Semantically, the binding relation might be imagined to be materialized in some entity, the binding. Such a binding entity is constructed at run time and destroyed later, or might have indefinite extent.

class

object that determines the structure and behavior of a set of other objects called its instances

Note: The behavior is the set of operations that can be performed on an instance.

condition

object that represents a situation that has been (or might be) detected by a running program

definition point

textual point of an ISLISP text that is the start of an identifier's representation of an ISLISP object

direct instance

instance of a class but not an instance of one of its subclasses

Note: Every ISLISP object is direct instance of exactly one class, which is called its class . The set of all direct instances together with their behavior constitute a class.

dynamic

having an effect that is determined only through program execution and that cannot, in general, be determined statically

dynamic variable

variable whose associated binding is determined by the most recently executed active block that established it, rather than statically by a lexically apparent block according to the lexical principle

evaluation

computation of a form prepared for execution which results in a value and/or a side-effect

execution

sequence of (sometimes nested) activations

extension

implementation-defined modification to the requirements of this document that does not invalidate any ISLISP text complying with this document (except by prohibiting the use of one or more particular spellings of identifiers), does not alter the set of actions which are required to signal errors, and does not alter the status of any feature designated as implementation dependent

form

single, syntactically valid unit of program text, capable of being prepared for execution

function

ISLISP object that is called with arguments, performs a computation (possibly having side-effects), and returns a value

generic function

function whose application behavior is determined by the classes of the values of its arguments and which consists - in general - of several methods

identifier

lexical element (lexeme) which designates an ISLISP object

Note: In the data structure representation of ISLISP texts, identifiers are denoted by symbols.

immutable binding

binding in which the relation between an identifier and the object represented by this identifier cannot be changed

Note: It is a violation if there is attempt to change an immutable binding (error-id. immutable-binding ).

immutable object

object which is not subject to change, either because no operator is provided that is capable of effecting such change, or because some constraint exists which prohibits the use of an operator that might otherwise be capable of effecting such a change

Note: Except as explicitly indicated otherwise, a conforming processor is not required to detect attempts to modify immutable objects; the consequences are undefined if an attempt is made to modify an immutable object.

implementation defined

feature, possibly differing between different ISLISP processors, but completely defined for every processor

implementation dependent

feature, possibly differing between different ISLISP processors, but not necessarily defined for any particular processor

Note: A conforming ISLISP text must not depend upon implementation-dependent features.

inheritance

relation between a class and its superclass which maps structure and behavior of the superclass onto the class

Note: ISLISP supports a restricted form of multiple inheritance; i.e. , a class may have several direct superclasses at once.

instance

〈class〉 either a direct instance of a class or an instance of one of its subclasses

literal

object whose representation occurs directly in a program as a constant value

metaclass

class whose instances are themselves classes

method

case of a generic function for a particular parameter profile, which defines the class-specific behavior and operations of the generic function

object

anything that can be created, destroyed, manipulated, compared, stored, input, or output by the ISLISP processor

Note 1: In particular, functions are ISLISP objects.

Note 2: Objects that can be passed as arguments to functions, can be returned as values, can be bound to variables, and can be part of structures, are called first-class objects.

operator

first element of a compound form, which is either a reserved name that identifies the form as a special form, or the name of a macro, or a lambda expression, or else an identifier in the function namespace

operator position

occurrence of a text unit as the first element in a form

parameter profile

parameter list of a method, where each formal parameter is accompanied by its class name

Note: If a parameter is not accompanied by a class name, it belongs to the most general class.

place

location where objects can be stored and retrieved later

setf . If used this way an object is stored in the place. If the form is not used as first argument of setf the stored object is retrieved. The cases are listed in the description of Note: Places are designated by forms which are permitted as the first argument of. If used this way an object is stored in the place. If the form is not used as first argument ofthe stored object is retrieved. The cases are listed in the description of setf

process

execution of an ISLISP text prepared for execution

processor

system or mechanism, that accepts an ISLISP text (or an equivalent data structure) as input, prepares it for execution, and executes the result to produce values and side-effects

program

aggregation of expressions to be evaluated, the specific nature of which depends on context

Note: Within this document, the term “program” is used only in an abstract way; there is no specific syntactic construct that delineates a program.

scope

〈identifier〉 the textual part of a program where the meaning of that identifier is defined; i.e., there exists an ISLISP object designated by this identifier

slot

named component of an instance which can be accessed using the slot accessors Note: The structure of an instance is defined by the set of its slots.

text

text that complies with the requirements of this document (i.e., with the syntax and static semantics of ISLISP)

Note: An ISLISP text consists of a sequence of toplevel forms.

toplevel form

any form that either is not nested in any other form or is nested only in progn forms

toplevel scope

scope in which a complete ISLISP text unit is processed

writer

method associated with a slot of a class, whose task is to bind a value with a slot of an instance of that class

Notation and conventions

For a clear definition of, and a distinction between, syntactic and semantic concepts, several levels of description abstraction are used in the following.

There is a correspondence from ISLISP textual units to their ISLISP data structure representations. Throughout this document the text and the corresponding ISLISP objects (data structures) are addressed simultaneously. ISLISP text can be seen as an external specification of ISLISP data structures. To distinguish between the two representations different concepts are used. When textual representation is discussed, textual elements (such as identifiers, literals, and compound forms) are used; when ISLISP objects are discussed, objects (such as symbols and lists) are used.

The constituents of ISLISP text are called forms. A form can be an identifier, a literal, or a compound form. A compound form can be a function application form, a macro form, a special form, or a defining form.

An identifier is represented by a symbol. A compound form is represented by a non-null list. A literal is represented by neither a symbol nor a list, and so is neither an identifier nor a compound form; for example, a number is a literal.

An object is prepared for execution; this might include transformation or compilation, including macro expansion. The method of preparation for execution and its result are not defined in this document (with exception of the violations to be detected). After successful preparation for execution the result is ready for execution. The combination of preparation for execution and subsequent execution implements ISLISP's evaluation model. The term “evaluation” is used because ISLISP is an expression language—each form has a value which is used to compute the value of the containing form. The results obtained when an entity is prepared for execution are designated throughout this document by the construction prepared entity ; e.g., prepared form, prepared special form.

A “cond special form” becomes a “prepared cond” by preparation for execution.

In the examples, the metasymbol “⇒” designates the result of an actual evaluation. For example:

(+ 3 4) ⇒ 7

The metasymbol → identifies the class that results from the evaluation of a form having a given pattern. For example:

(+ i 1 i 2 ) → integer

Given a form pattern (usually defined by its constant parts, the function name or special operator), → relates it to the class to which the result of the evaluation of all matching forms belong.

Form patterns or forms which are equivalent are related by ≡.

The following notational conventions for form patterns are used:

( f-name argument *) → result-class

In this notation, words written in italics are non-terminal (pattern variables). f-name is always terminal: Specific function names, special operators, defining form names, or generic function names are always presented.

An underlined term (like the name in a defining form) in this notation, indicates an expression that is not evaluated. If a form might or might not be evaluated (like one of the then-form or else-form in an if), this is indicated explicitly in the text.

Class names are uniformly denoted as follows: class-name. For example, list is the name of a class; this is usually spoken aloud as list class.

Notes, appearing as Note: note-text, in this document have no effect on the language. They are for better understanding by the human reader.

Regarding the pattern variables and the extensions of above, the following conventions are also adopted:

term + denotes one or more occurrences of term ; term * denotes zero or more occurrences of term ; [ term ] denotes at most one occurrence of term , commonly one says that term is optional; { term 1 term 2 …} denotes grouping of terms . term 1 | term 2 | … denotes grouping of alternative terms .

The following naming conventions are used to denote forms whose arguments obey the respective class restrictions:

array , array 1 , … array j , … basic-array cons , cons 1 , … cons j , … cons list , list 1 , … list j , … list obj , obj 1 , … obj j , … object sequence , sequence 1 , … sequence j , … basic-vector or list (see §25) stream , stream 1 , … stream j , … stream string , string 1 , … string j , … string char , char 1 , … char j , … character function , function 1 , … function j , … function class , class 1 , … class j , … class symbol , symbol 1 , … symbol j , … symbol x , x 1 , … x j , … number z , z 1 , … z j , … integer

In this document the conventions detailed below are used, except where noted:

-p Predicates—sometimes called boolean functions —usually have names that end in a -p. Usually every class name has a characteristic function, whose name is built as name-p if name is hyphenated (generic-function-p), or namep if name is not hyphenated (symbolp). Note that not all functions whose names end with p are predicates. create- Usually a built-in class name has a constructor function, which is called create- name . def This is used as the prefix of the defining operators. set- Within this document, any functions named set- name are writers for a place, for which there is a corresponding reader named name .

For any kind of entity in the language, the phrase entity-kind name refers to the entity of kind entity-kind denoted by name. For example, the phrases function name , constant name , or class name respectively mean the function, constant, or class denoted by name.

Lexemes

An ISLISP text is built up from lexemes. Lexemes are built up from at least the following characters (see §20):

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 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 0 1 2 3 4 5 6 7 8 9 + - < > / * & = . ? _ ! $ % : @ [ ] ^ { } ~ #

Additional characters are implementation defined.

The following characters are individual lexemes (see §16 and §21.1):

( ) , ' `

The following character tuples (where n is a sequence of digits) are individual lexemes (see §12.7, §16, and §22.1):

#' #( ,@ #B #b #O #o #X #x #na #nA

The textual representations of symbols (see §18), numbers (see §19), characters (see §20), and strings (see §24) are lexemes.

\ (single escape) and | (multiple escape) are special characters. They may occur in some lexemes (identifiers and string literals).

Other lexemes are separated by delimiters. Delimiters are separators along with the following characters:

( ) ` , '

The effect of delimiting is disestablished inside a string (see §24) or inside a corresponding pair of multiple escape characters (see §18) or for the character immediately following #\.

Separators

Separators are as follows: blank, comments, newline, and an implementation-defined set of characters, (e.g., tabs). Separators have no meaning and can be replaced by each other without changing the meaning of the ISLISP text.

The character semicolon (;) is the comment begin character. That is, the semicolon and all the characters up to and including the end-of-line form a comment.

A character sequence beginning with #| and ending with |# is a comment. Such comments may be nested.

Being a separator, a comment cannot occur inside a lexeme.

Textual representation

The textual representation of an object is machine independent. The following are some of the textual representations of the ISLISP objects. This representation is readable by the read function. Lexemes are described in §6

Null The object nil is the only object whose class is null . Upon input, it may be written as nil or () . It is implementation defined whether nil prints as nil or () . List Proper lists are those lists terminated by nil . Usually they are denoted as ( obj 1 obj 2 ... obj n ). A dotted list ( i.e. , a list whose last tail is not nil ) appears as ( obj 1 obj 2 ... obj n . obj n+1 ). Character An instance of the character class is represented by #\ ? , where ? is the character in question. There are two special standard characters that are not represented in this way, namely newline and space, whose representations are #

ewline and #\space, respectively. Cons A cons is expressed as ( car . cdr ), where the car and cdr are objects. Integer An integer (radix 10) is represented as a sequence of digits optionally preceded by a + or - sign. If the number is represented in binary radix (or in octal or hexadecimal) then the textual representation is preceded by #b (or #o or #x, respectively). Float A ﬂoating point number is written in one of the following formats: [ s ] dd … d . dd … d [ s ] dd … d . dd … d E[ s ] dd … d [ s ] dd … d . dd … d e[ s ] dd … d [ s ] dd … d E[ s ] dd … d [ s ] dd … d e[ s ] dd … d where s is either + or - , and d is one of 0 – 9 . For example: 987.12, +12.5E-13, -1.5E12, 1E32 Vector A vector of class general-vector is written as #( obj 1 … obj n ). Array An array of class general-array* or general-vector can be written on input as #na (where n is an integer indicating the number of dimensions of the array) followed by a nested structure of sequences denoting the contents of the array. This structure is defined as follows. If n = 1 the structure is simply (obj 1 ... obj n ). If n > 1 and the dimensions are n 1 n 2 ..., the structure is (str 1 ... str n ), where the str i are the structures of the n 1 subarrays, each of which has dimensions (n 2 ...). As an example, the representation of (create-array '(2 3 4) 5) is as follows: #3a(((5 5 5 5) (5 5 5 5) (5 5 5 5)) ((5 5 5 5) (5 5 5 5) (5 5 5 5))) On output (see format), arrays of class general-vector will be printed using #(...) notation. String A string is represented by the sequence of its characters enclosed in a pair of "'s. For example: "abc". Special characters are preceded with a backslash as an escape character. Symbol A named symbol is represented by its print name. Vertical bars (|) might need to enclose the symbol if it contains certain special characters; see §18. The notation, if any, used for unnamed symbols is implementation defined.

There are objects which do not have a textual representation, such as a class or an instance of the function class.

Reserved identifiers

Symbols whose names contain a colon (:) or an ampersand (&) are reserved and may not be used as identifiers. Symbols whose names start with colon (:) are called keywords.

Errors

An error is a situation arising during execution in which the processor is unable to continue correct execution according to the semantics defined in this document. The act of detecting and reporting such an error is called signaling the error.

A violation is a situation arising during preparation for execution in which the textual requirements of this document are not met. A violation shall be detected during preparation for execution.

Classes of error specification

The wording of error specification in this document is as follows:

an error shall be signaled An implementation shall detect an error of this kind no later than the completion of execution of the form having the error, but might detect them sooner (e.g., when the code is being prepared for execution). Evaluation of the current form shall stop. If no active handler is established by with-handler, it is implementation defined whether the entire running process exits, a debugger is entered, or control is transferred elsewhere within the process. the consequences are undefined This means that the consequences are unpredictable. The consequences may range from harmless to fatal. No conforming ISLISP text may depend on the results or effects. A conforming ISLISP text must treat the consequences as unpredictable. In places where must, must not, or may not are used, then this is equivalent to stating that the consequences are undefined if the stated requirement is not met and no specific consequence is explicitly stated. An implementation is permitted to signal an error in this case.

For indexing and cross-referencing convenience, errors in this document have an associated error identification label, notated by text such as (error-id. sample). The text of these labels has no formal significance to ISLISP texts or processors; the actual class of any object which might be used by the implementation to represent the error and the text of any error message that might be displayed is implementation dependent.

Pervasive error types

Most errors are described in detail in the contect in which they occur. Some error types are so pervasive that their detailed descriptions are consolidated here rather than repeated in full detail upon each occurrence.

Domain error: an error shall be signaled if the object given as argument of a standard function for which a class restriction is in effect is not an instance of the class which is required in the definition of the function (error-id. domain-error ). Arity error: an error shall be signaled if a function is activated with a number of arguments which is different than the number of parameters as required in the function definition (error-id. arity-error ). Undefined entity error: an error shall be signaled if the entity denoted by an identifier does not exist when a reference to that entity is made (error-id. undefined-entity ). Two commonly occuring examples of this type of error are undefined-function and unbound-variable .

This list does not exhaust the space of error types. For a more complete list, see §29.4.

Classes

In ISLISP, data types are covered by the class system. A class is an object that determines the structure and behavior of a set of other objects, which are called its instances. Every ISLISP object is an instance of a class. The behavior is the set of operations that can be performed on an instance.

A class can inherit structure and behavior from other classes. A class whose definition refers to other classes for the purpose of inheriting from them is said to be a subclass of each of those classes. The classes that are designated for purposes of inheritance are said to be superclasses of the inheriting class.

A class can be named by an identifier. For example, this identifier can be used as a parameter specializer in method definitions. The class special form can be used to refer to access the class object corresponding to its name.

A class C 1 is a direct superclass of a class C 2 if C 2 explicitly designates C 1 as a superclass in its definition, or if C 1 is defined by this document to be a direct superclass of C 2 (for example, by use of a directed arrow from C 1 to C 2 in Figure 1). In this case C 2 is a direct subclass of C 1 . A class C n is a superclass of a class C 1 if there exists a series of classes C 2 , … , C n−1 such that C i+1 is a direct superclass of C i for 1 ≤ i < n. In this case, C 1 is a subclass of C n . A class is considered neither a superclass nor a subclass of itself. That is, if C 1 is a superclass of C 2 , then C 1 ≠ C 2 . The set of classes consisting of some given class C along with all of its superclasses is called C and its superclasses.

If a user-defined class C inherits from two classes, C 1 and C 2 , the only superclasses that C 1 and C 2 may have in common are standard-object or object. This allows a restricted form of multiple inheritance.

Every ISLISP object is a direct instance of exactly one class which is called its class.

An instance of a class is either a direct instance of that class or an instance of one of its subclasses.

Classes are organized into a directed acyclic graph defined by the subclass relation. The nodes are classes and there is an edge from C 1 to C 2 iff C 2 is direct subclass of C 1 . This graph is called the inheritance graph. It has as root the class object, the only class with no superclass.

Therefore it is the superclass of every class except itself. The class named standard-object is an instance of the class standard-class and is a superclass of every class that is an instance of standard-class except itself.

Each class has a class precedence list, which is a total ordering on the set of the given class and its superclasses. The total ordering is expressed as a list ordered from most specific to least specific. The class precedence list is used in several ways. In general, more specific classes can shadow, or override, features that would otherwise be inherited from less specific classes. The method selection and combination process uses the class precedence list to order methods from most specific to least specific.

Metaclasses

Classes are represented by objects that are themselves instances of classes. The class of the class of an object is termed the metaclass of that object. The term metaclass is used to refer to a class that has instances that are themselves classes.

object basic-array basic-array* general-array* basic-vector general-vector string built-in-class character function generic-function standard-generic-function list cons null symbol number float integer serious-condition error arithmetic-error ; division-by-zero floating-point-overflow floating-point-underflow control-error parse-error program-error domain-error undefined-entity unbound-variable undefined-function simple-error stream-error end-of-stream storage-exhausted standard-class standard-object stream

Figure 1. Class Inheritance

The metaclass determines the form of inheritance used by the classes that are its instances and the representation of the instances of those classes.

The ISLISP Object System provides the following predefined metaclasses:

The class standard-class is the default class of classes defined by defclass.

is the default class of classes defined by defclass. The class built-in-class is the class whose instances are classes that have special implementations or restricted capabilities. For example, it is not possible to define subclasses of a built-in class.

Predefined classes

The following classes are primitive classes in the class system (i.e., predefined classes that are not metaclasses):

arithmetic-error

basic-array

basic-array*

basic-vector

character

cons

control-error

division-by-zero

domain-error

end-of-stream

error

float

floating-point-overflow

floating-point-underflow

function

general-array*

general-vector

generic-function

integer

list

null

number

object

parse-error

program-error

serious-condition

simple-error

standard-generic-function

standard-object

storage-exhausted

stream

stream-error

string

symbol

unbound-variable

undefined-entity

undefined-function

The classes standard-class and built-in-class are predefined metaclasses.

A user-defined class, defined by defclass, must be implemented as an instance of standard-class. A predefined class can be implemented either as an instance of standard-class (as if defined by defclass) or as an instance of built-in-class.

Figure 1 shows the required inheritance relationships among the classes defined by ISLISP. For each pair of classes C 1 and C 2 in this figure, if C 1 is linked directly by an arrow to C 2 , C 1 is a direct superclass of C 2 (and C 2 is a direct subclass of C 1 ). Additional relationships might exist, subject to the following constraints:

It is implementation defined whether standard-generic-function is a subclass of the class standard-object .

is a subclass of the class . Except as described in Figure 1 and the above constraint on standard-generic-function , no other subclass relationships exist among the classes defined in this document. However, additional implementation-specific subclass relationships may exist between implementation-specific classes and classes defined in this document.

, no other subclass relationships exist among the classes defined in this document. However, additional implementation-specific subclass relationships may exist between implementation-specific classes and classes defined in this document. The class precedence list for null observes the partial order null , symbol , list , object .

observes the partial order , , , . Users may define additional classes using defclass .

A built-in class is one whose instances have restricted capabilities or special representations. The defclass defining form must not be used to define subclasses of a built-in class. An error shall be signaled if create is called to create an instance of a built-in class.

A standard class is an instance of standard-class, and a built-in class is an instance of built-in-class.

A standard class defined with no direct superclasses is guaranteed to be disjoint from all of the classes in the figure, except for the classes named standard-object and object.

The class function is the class of all functions. The class standard-generic-function is the default class of all generic functions.

Standard classes

Slots

An object that has standard-class as its metaclass has zero or more named slots. The slots of an object are determined by the class of the object. Each slot can hold one object as its value. The name of a slot is an identifier.

When a slot does not have a value, the slot is said to be unbound. The consequences are undefined if an attempt is made to retrieve the value of an unbound slot.

Storing and retrieving the value of a slot is done by generic functions defined by the defclass defining form.

All slots are local; i.e., there are no shared slots accessible by several instances.

A class is said to define a slot with a given name when the defclass defining form for that class contains a slot specifier with that name. Defining a slot does not immediately create a slot; it causes a slot to be created each time an instance of the class is created.

A slot is said to be accessible in an instance of a class if the slot is defined by the class of the instance or is inherited from a superclass of that class. At most one slot of a given name can be accessible in an instance. A detailed explanation of the inheritance of slots is given in the section §15.1.3.

Creating instances of classes

The generic function create creates and returns a new instance of a class. ISLISP provides several mechanisms for specifying how a new instance is to be initialized. For example, it is possible to specify the initial values for slots in newly created instances by providing default initial values. Further initialization activities can be performed by methods written for generic functions that are part of the initialization protocol.

Scope and extent

In describing ISLISP, the notions of scope and extent are useful. The first is a syntactic concept, the latter is a semantic concept. Although syntactic constructs, especially identifiers, are used to refer to runtime entities (i.e., objects arising during execution), a single entity cannot have both scope and extent. Scope is a feature of an identifier, referring to that textual part of an ISLISP text (see §4.38 and §5) within which this identifier occurs with unique meaning. Extent refers to the interval of execution time during which a certain object exists.

A namespace is a mapping from identifiers to meanings. In ISLISP there are six namespaces: variable, dynamic variable, function, class, block, and tagbody tag. It is therefore possible for a single identifier to have any or all of these six meanings, depending on the context. For example, an identifier's meaning is determined by the function namespace when the identifier appears in the operator position of a function application form, whereas the same identifier's meaning is determined by the variable namespace if it appears in an argument position in the same form.

The lexical principle

ISLISP is designed following the principle of lexical visibility. This principle states that an ISLISP text must be structured in properly nested lexical blocks of visibility. Within a block, all defined identifiers of that block and of all enclosing outer blocks are visible. Each identifier in a namespace has the meaning determined by the innermost block that defines it.

ISLISP also supports a form of dynamic binding. Dynamic bindings are established and accessed by a separate mechanism (i.e., defdynamic, dynamic-let, and dynamic). The dynamic value associated with such an identifier is the one that was established by the most recently executed active block that established it, where an active block is one that has been established and not yet disestablished. Because a separate mechanism is used, the lexical meaning of and the dynamic value associated with an identifier are simultaneously accessible wherever both are defined.

Scope of identifiers

The scope of an identifier is that part of an ISLISP text where the meaning of the identifier is defined. It starts textually with the definition point—a point that is specified individually for each form that establishes an identifier. Only identifiers can have a scope.

For each namespace, if an identifier has scope s a and an identical identifier (in the same namespace) has nested scope s b , then the scope s b of the inner identifier and every scope contained in it are not part of the scope s a . It is said that the inner scope shadows the outer scope.

Each complete ISLISP text unit is processed in a scope called the toplevel scope.

In each namespace, nested binding forms shadow outer binding forms and defining forms.

(let ((a1 f-a1) ... (x f-x) ... (z1 f-z1)) ; ... ; now a1...x...z1 are applicable, their scope begins here (let ((a2 f-a2) ; a1...x...z1 might be defined newly, but: ... ; the outer a1...x...z1 are still usable (x f-x2) ; the inner a2...x...z2 are not yet usable ... (z2 f-z2)) ; the scope of the outer x becomes shadowed ; the scope for the inner a2...x...z2 starts ... ; now outer a1, z1 and inner a2...x...z2 are applicable ) ; scopes of a2...x...z2 end here ... ; scope of outer x becomes unshadowed ) ; scopes of a1...x...z1 end here Figure 2. Scope Example

Some specific scope rules

The toplevel scope is the scope of identifiers of required built-in functions, special operators, defining operators, and constants.

Reserved identifiers are not subject to the lexical principle, because they are not identifiers. They cannot be defined or bound. See §8.

Extent

Complementary to scope which is a syntactic concepts, extent is a semantic concept: It describes the lifetime of entities.

Objects are created at some time during execution. In most cases, it is undetermined when an object ends its existence: its lifetime begins when the object is created and ends when reference to it is no longer possible (and the object is subject to garbage collection). In this case the object is said to have indefinite extent.

In other cases the processor creates entities that are associated with prepared text. The lifetime of such objects begins at the activation point of a defining construct and ends at the end of activation; in this case the object is said to have dynamic extent.

During execution, defining forms and the following binding forms create bindings at their activation points:

The bindings established by defining forms may have indefinite extent. Even in local binding constructs, bindings might not vanish upon activation end of the prepared block—if one or more function objects are created during execution of the prepared block that contain references to those bindings, the bindings will have a lifetime equal to the longest lifetime of those function objects.

Example: (defun copy-cell (x) (cons (car x) (cdr x))) The scope of the identifier x is the body alone—i.e., (cons (car x) (cdr x)). The meaning of x is defined for the entire body. x, as identifier, cannot have an extent. The defun form for copy-cell is prepared for execution and thereby copy-cell becomes a prepared function. During execution the prepared function copy-cell might be activated. Activation in this case results in the creation of a binding between the variable denoted by x and the object which is used as argument. The binding of x is an entity whose extent lasts from the activation point to the activation end of the function. (In general the extent of a binding can last beyond the activation end, but this does not occur in this simple case.) We say that the binding of x is established upon activation of the function and is disestablished at activation end.

Forms and evaluation

Forms

Execution presupposes successful preparation for execution of an ISLISP text subject to the evaluation model. Execution is an activation of a prepared text form that results in a value and perhaps in some side-effects.

An ISLISP text is a sequence of forms.

Throughout this document the value a form returns is described, but in general a form might not return if one of its subforms executes a non-local exit (see §14.7.1). Therefore, it should be understood that all such descriptions implicitly include the provision that if the form returns, a particular value is returned.

The following are valid forms in ISLISP:

Compound forms Special forms Defining forms Function application forms Macro forms

Identifiers

Literals

A form, when evaluated, returns an object as its value, though some forms may not return (e.g., return-from).

A compound form is written as (operator argument*). The operator must be a special operator, a defining operator, an identifier, or a lambda expression. The identifier names a function, a macro, or a generic function. It is a violation if operator is a literal.

A toplevel form is a form that is either not lexically nested within another form or is lexically nested only within one or more progn forms. Special forms and function application forms at toplevel are called set-up forms. It is a violation if a defining form is not a toplevel form.

Function application forms

A function application form is a compound form whose operator is an identifier (naming a function) or whose operator is a lambda expression. All of the arguments are evaluated, from left to right, and the function is called with (or “applied to”) arguments that are, in the same order, the objects resulting from these evaluations. This document describes a function application form in the following format:

( function-name argument *) → result-class

This describes an ordinary function.

( generic-function-name argument *) → result-class

This describes a generic function.

( local-function-name argument *) → result-class

This describes an ordinary function that is available only in a specified lexical scope.

Special forms

A special form is a form whose arguments are treated in a special way; for example, arguments are not evaluated or are evaluated in a special order. It is implementation defined whether any special form is implemented as a macro (see §12.5 and §16). Special forms are recognized because they have a special operator in their operator position. The following are special operators:

There might be additional, implementation-defined special operators.

This document describes the evaluation of special forms in the following format:

( special-operator argument *) → result-class

Defining forms

A defining form is a toplevel special form (see §12.3) that establishes a binding between name and an object which is the result of handling the arguments according to the semantics implied by defining-form-name; it is a violation if a defining form is not a toplevel form. For each namespace, defining forms can occur at most once for the same name and, in case of method definitions for the same parameter profile. A defining form is a compound form whose operator is a defining operator. These are the defining operators:

This document describes defining forms in the following format:

( defining-form-name name argument *) → symbol

Macro forms

Macro forms are expanded during preparation for execution.

For information on how macros are processed, see §16.

The evaluation model

This section provides an operational model of the process of evaluation.

The process of evaluation has two steps: A valid ISLISP text is first prepared for execution, and then the prepared text is executed. Both the process of preparing the text for execution and the properties of a prepared text are implementation dependent, except that all macros have been expanded in the prepared text (see §16). The process of execution which follows is described in terms of fully macroexpanded forms.

A prepared form is executed as follows:

If the form is a literal , the result is the form itself.

, the result is the form itself. If the form is an identifier , the result is the object denoted by the identifier in the variable namespace of the current lexical environment. An error shall be signaled if no binding has been established for the identifier in the variable namespace of current lexical environment (see §9.2) (error-id. unbound-variable ).

, the result is the object denoted by the in the variable namespace of the current lexical environment. An error shall be signaled if no binding has been established for the identifier in the variable namespace of current lexical environment (see §9.2) (error-id. ). If the form is a compound form, then one of the following cases must apply: If the operator is a special operator , then the form is a special form and its arguments are evaluated according to the definition of the special operator. For example, if first evaluates its condition expression and, depending on the result obtained, it then evaluates the “then” form or the “else” form. If the operator names a defining form, then the first argument is an identifier. The remaining arguments are handled according to the specification of the defining form and the resulting object is used to establish a binding between the identifier and that object in the appropriate namespace. If the operator is a lambda-expression, then the arguments are evaluated. The order of evaluation of the arguments is sequentially from left to right. Then the function denoted by the lambda-expression is invoked with the evaluated arguments as actual parameters. The result is the value returned by the function, if it returns. ((lambda (x) (+ x x)) 4) ⇒ 8 Otherwise, the compound form is a function application form. The operator position of the form is an identifier; it will be evaluated in the function namespace to produce a function to be called. An error shall be signaled if no binding has been established for the identifier in the function namespace of the current lexical environment (see §9.2) (error-id. undefined-function ). The arguments are evaluated in order from left to right. Then the function is invoked with the evaluated arguments as actual parameters. The result is the value returned by the function, if it returns.

Otherwise, an error shall be signaled (error-id. undefined-function ).

See §9.2 for descriptions of error situations that might occur during execution of the above cases.

Functions

A function can receive some objects as arguments upon activation. If a function returns, it returns an object as its value. A function binding can be established in one of the following ways:

by using function defining forms; i.e. , the defun , defgeneric , and defclass defining forms

, the , , and defining forms by using labels and flet special forms

( functionp obj ) → boolean

Returns t if obj is a (normal or generic) function; otherwise, returns nil. obj may be any ISLISP object.

(functionp (function car)) ⇒ t

Function bindings are entities established during execution of a prepared labels or flet forms or by a function-defining form. A function binding is an association between an identifier, function-name, and a function object that is denoted by function-name—if in operator position—or by (function function-name) elsewhere.

( function function-name ) → function

#' function-name → function

This special form denotes a reference to the function named by function-name. This special form is used to refer to identifiers defined by function-defining forms, labels, or flet which are not in operator position.

(function function-name) can be written as #'function-name.

It returns the function object named by function-name.

An error shall be signaled if no binding has been established for the identifier in the function namespace of current lexical environment (see §9.2) (error-id. undefined-function). The consequences are undefined if the function-name names a macro or special form.

(funcall (function -) 3) ⇒ -3 (apply #'- '(4 3)) ⇒ 1

( lambda lambda-list form *) → function

Where: lambda-list ::= ( identifier* [ &rest identifier ]) | ( identifier* [ :rest identifier ])

and where no identifier may appear more than once in lambda-list.

Execution of the lambda special form creates a function object.

The scope of the identifiers of the lambda-list is the sequence of forms form*, collectively referred to as the body.

When the prepared function is activated later (even if transported as object to some other activation) with some arguments, the body of the function is evaluated as if it was at the same textual position where the lambda special form is located, but in a context where the lambda variables are bound in the variable namespace with the values of the corresponding arguments. A &rest or :rest variable, if any, is bound to the list of the values of the remaining arguments. An error shall be signaled if the number of arguments received is incompatible with the specified lambda-list (error-id. arity-error).

Once the lambda variables have been bound, the body is executed. If the body is empty, nil is returned otherwise the result of the evaluation of the last form of body is returned if the body was not left by a non-local exit (see §14.7.1).

If the function receives a &rest or :rest parameter R, the list L 1 to which that parameter is bound has indefinite extent. L 1 is newly allocated unless the function was called with apply and R corresponds to the final argument, L 2 , to that call to apply (or some subtail of L 2 ), in which case it is implementation defined whether L 1 shares structure with L 2 .

((lambda (x y) (+ (* x x) (* y y))) 3 4) ⇒ 25 ((lambda (x y &rest z) z) 3 4 5 6) ⇒ (5 6) ((lambda (x y :rest z) z) 3 4 5 6) ⇒ (5 6) (funcall (lambda (x y) (- y (* x y))) 7 3) ⇒ -18

( labels (( function-name lambda-list form *)*) body-form *) → object

( flet (( function-name lambda-list form *)*) body-form *) → object

The flet and labels special forms allow the definition of new identifiers in the function namespace for function objects.

In a labels special form the scope of an identifier function-name is the whole labels special form (excluding nested scopes, if any); for the flet special form, the scope of an identifier is only the body-form*. Within these scopes, each function-name is bound to a function object whose behavior is equivalent to (lambda lambda-list form*), where free identifier references are resolved as follows:

For a labels form, such free references are resolved in the lexical environment that was active immediately outside the labels form augmented by the function bindings for the given function-names ( i.e. , any reference to a function function-name refers to a binding created by the labels ).

form, such free references are resolved in the lexical environment that was active immediately outside the form augmented by the function bindings for the given ( , any reference to a function refers to a binding created by the ). For a flet form, free identifier references in the lambda -expression are resolved in the lexical environment that was active immediately outside the flet form ( i.e. , any reference to a function function-name are not visible).

During activation, the prepared labels or flet establishes function bindings and then evaluates each body-form in the body sequentially; the value of the last one (or nil if there is none) is the value returned by the special form activation.

No function-name may appear more than once in the function bindings.

(labels ((evenp (n) (if (= n 0) t (oddp (- n 1)))) (oddp (n) (if (= n 0) nil (evenp (- n 1))))) (evenp 88)) ⇒ t (flet ((f (x) (+ x 3))) (flet ((f (x) (+ x (f x)))) (f 7))) ⇒ 17

( apply function obj * list ) → object

Applies function to the arguments, obj*, followed by the elements of list, if any. It returns the value returned by function.

An error shall be signaled if function is not a function (error-id. domain-error). Each obj may be any ISLISP object. An error shall be signaled if list is not a proper list (see §7) (error-id. improper-argument-list).

(apply (if (< 1 2) (function max) (function min)) 1 2 (list 3 4)) ⇒ 4 (defun compose (f g) (lambda (:rest args) (funcall f (apply g args))))) ⇒ compose (funcall (compose (function sqrt) (function *)) 12 75) ⇒ 30

( funcall function obj *) → object

Activates the specified function function and returns the value that the function returns. The ith argument (2 ≤ i) of funcall becomes the (i − 1)th argument of the function. funcall could have been defined using apply as follows:

(defun funcall (function :rest arguments) (apply function arguments))

An error shall be signaled if function is not a function (error-id. domain-error). Each obj may be any ISLISP object.

(let ((x '(1 2 3))) (funcall (cond ((listp x) (function car)) (t (lambda (x) (cons x 1)))) x)) ⇒ 1

Defining operators

Although the names defined by defining forms can be used throughout the current toplevel scope, the prepared toplevel forms in an ISLISP text unit are executed sequentially from left to right.

Two defining forms with the same identifier in the same namespace are not allowed in one toplevel scope.

( defconstant name form ) → symbol

This form is used to define a named constant in the variable namespace of the current toplevel scope. The scope of name is the entire current toplevel scope except the body form.

Although name is globally constant, a variable binding for name can be locally established by a binding form.

The result of the evaluation of form is bound to the variable named by name. The binding and the object created as the result of evaluating the second argument are immutable. The symbol named name is returned.

(defconstant e 2.7182818284590451) ⇒ e e ⇒ 2.7182818284590451 (defun f () e) ⇒ f (f) ⇒ 2.7182818284590451

( defglobal name form ) → symbol

This form is used to define an identifier in the variable namespace of the current toplevel scope. The scope of name is the entire current toplevel scope except the body form.

form is evaluated to compute an initializing value for the variable named name. Therefore, defglobal is used only for defining variables and not for modifying them. The symbol named name is returned.

A lexical variable binding for name can still be locally established by a binding form; in that case, the local binding lexically shadows the outer binding of name defined by defglobal.

(defglobal today 'wednesday) ⇒ today today ⇒ wednesday (defun what-is-today () today) ⇒ what-is-today (what-is-today) ⇒ wednesday (let ((what-is-today 'thursday)) (what-is-today)) ⇒ wednesday (let ((today 'thursday)) (what-is-today)) ⇒ wednesday

( defdynamic name form ) → symbol

This form is used to define a dynamic variable identifier in the dynamic variable namespace. The scope of name is the entire current toplevel scope except the body form.

The symbol named name is returned.

(defdynamic *color* 'red) ⇒ *color* (dynamic *color*) ⇒ red (defun what-color () (dynamic *color*)) ⇒ what-color (what-color) ⇒ red (dynamic-let ((*color* 'green)) (what-color)) ⇒ green

( defun function-name lambda-list form *) → symbol

The defun-form defines function-name as an identifier in the function namespace; function-name is bound to a function object equivalent to (lambda lambda-list form*).

The scope of function-name is the whole current toplevel scope. Therefore, the definition of a function admits recursion, occurrences of function-name within the form* refer to the function being defined. The binding between function-name and the function object is immutable.

defun returns the function name which is the symbol named function-name. The free identifiers in the body form* (i.e., those which are not contained in the lambda list) follow the rules of lexical scoping.

(defun caar (x) (car (car x))) ⇒ caar

Predicates

Boolean values

The values t and nil are called booleans. t denotes true, and nil is the only value denoting false. Predicates, also called boolean functions, are functions that return t when satisfied and nil otherwise.

Any object other than nil is treated as true (not just t). When objects are treated as true or nil this way they are called quasi-booleans.

t is an identifier naming the symbol t, and nil is an identifier naming the symbol nil (which is also the empty list). nil is the unique instance of the null class.

Like boolean functions, the and and or special forms return truth values; however, these truth values are nil when the test is not satisfied and a non-nil value otherwise. The result of and and or are quasi-booleans.

t → symbol

nil → null

t is a named constant whose value is the symbol t itself. nil is a named constant whose value is the symbol nil itself.

Class predicates

The following functions are one-argument class membership predicates:

In addition, the function instancep is a two-argument predicate that tests membership in an arbitrary class.

Equality

( eq obj 1 obj 2 ) → boolean

( eql obj 1 obj 2 ) → boolean

eq and eql test whether obj 1 and obj 2 are same identical object. They return t if the objects are the same; otherwise, they return nil. Two objects are the same if there is no operation that could distinguish them (without modifying them), and if modifying one would modify the other the same way.

For eq, the consequences are implementation defined if both obj 1 and obj 2 are numbers or both are characters. For eql the meaning for numbers and characters is defined as follows:

If obj 1 and obj 2 are numbers, eql tests whether they are direct instances of the same class and have the same value. If an implementation supports positive and negative zeros as distinct values, then (eql 0.0 -0.0) returns nil. When the syntax -0.0 is read and it is interpreted as the value 0.0 then (eql 0.0 -0.0) returns t.

If obj 1 and obj 2 are characters, eql tests whether they are the same character (see char= ).

(eql () ()) ⇒ t (eq () ()) ⇒ t (eql '() '()) ⇒ t (eq '() '()) ⇒ t (eql 'a 'a) ⇒ t (eq 'a 'a) ⇒ t (eql 'a 'A) ⇒ t (eq 'a 'A) ⇒ t (eql 'a 'b) ⇒ nil (eq 'a 'b) ⇒ nil (eql 'f 'nil) ⇒ nil (eq 'f 'nil) ⇒ nil (eql 2 2) ⇒ t (eq 2 2) ⇒ nil or t (implementation-defined) (eql 2 2.0) ⇒ nil (eq 2 2.0) ⇒ nil (eql 100000000 100000000) ⇒ t (eq 100000000 100000000) ⇒ nil or t (implementation-defined) (eql 10.00000 10.0) ⇒ t (eq 10.00000 10.0) ⇒ nil or t (implementation-defined) (eql (cons 1 2) (cons 1 2)) ⇒ nil (eq (cons 1 2) (cons 1 2)) ⇒ nil (let ((x '(a))) (eql x x)) ⇒ t (let ((x '(a))) (eq x x)) ⇒ t (eql '(a) '(a)) ⇒ nil or t (implementation-defined) (eq '(a) '(a)) ⇒ nil or t (implementation-defined) (let ((x '(b)) (y '(a b))) (eql x (cdr y))) ⇒ nil or t (implementation-defined) (let ((x '(b)) (y '(a b))) (eq x (cdr y))) ⇒ nil or t (implementation-defined) (eql '(b) (cdr '(a b))) ⇒ nil or t (implementation-defined) (eq '(b) (cdr '(a b))) ⇒ nil or t (implementation-defined) (let ((p (lambda (x) x))) (eql p p)) ⇒ t (let ((p (lambda (x) x))) (eq p p)) ⇒ t (let ((x "a")) (eql x x)) ⇒ t (let ((x "a")) (eq x x)) ⇒ t (eql "a" "a") ⇒ nil or t (implementation-defined) (eq "a" "a") ⇒ nil or t (implementation-defined) (let ((x "")) (eql x x)) ⇒ t (let ((x "")) (eq x x)) ⇒ t (eql "" "") ⇒ nil or t (implementation-defined) (eq "" "") ⇒ nil or t (implementation-defined) (eql #\a #\A) ⇒ nil (eq #\a #\A) ⇒ nil (eql #\a #\a) ⇒ t (eq #\a #\a) ⇒ nil or t (implementation-defined) (eql #\space #\Space) ⇒ t (eq #\space #\Space) ⇒ nil or t (implementation-defined) (eql #\space #\space) ⇒ t (eq #\space #\space) ⇒ nil or t (implementation-defined)

( equal obj 1 obj 2 ) → boolean

This function tests whether obj 1 and obj 2 are isomorphic—i.e., whether obj 1 and obj 2 denote the same structure with equivalent values. equal returns t if the test was satisfied, and nil if not. Specifically:

If obj 1 and obj 2 are direct instances of the same class, equal returns t if they are eql. Otherwise (if they are direct instances of the same class but not eql), the result is t if one of the following cases applies:

lists: either obj 1 and obj 2 are both the empty list (i.e., nil), or (and (equal (car obj1) (car obj2)) (equal (cdr obj1) (cdr obj2))) holds;

basic arrays: (equal (array-dimensions obj 1 ) (array-dimensions obj 2 )) holds and for every valid reference (aref obj 1 ind 1 ...ind n ) (equal (aref obj 1 ind 1 … ind n ) (aref obj 2 ind 1 … ind n )) is satisfied.

Otherwise the value is nil.

obj 1 and obj 2 may be any ISLISP objects.

(equal 'a 'a) ⇒ t (equal 2 2) ⇒ t (equal 2 2.0) ⇒ nil (equal '(a) '(a)) ⇒ t (equal '(a (b) c) '(a (b) c)) ⇒ t (equal (cons 1 2) (cons 1 2)) ⇒ t (equal '(a) (list 'a)) ⇒ t (equal "abc" "abc") ⇒ t (equal (vector 'a) (vector 'a)) ⇒ t (equal #(a b) #(a b)) ⇒ t (equal #(a b) #(a c)) ⇒ nil (equal "a" "A") ⇒ nil

Logical connectives

( not obj ) → boolean

This predicate is the logical “not” (or “¬”). It returns t if obj is nil and nil otherwise. obj may be any ISLISP object.

(not t) ⇒ nil (not '()) ⇒ t (not 'nil) ⇒ t (not nil) ⇒ t (not 3) ⇒ nil (not (list)) ⇒ t (not (list 3)) ⇒ nil

( and form *) → object

and is the sequential logical “and” (or “∧”). forms are evaluated from left to right until either one of them evaluates to nil or else none are left. If one of them evaluates to nil, then nil is returned from the and; otherwise, the value of the last evaluated form is returned. The form and is equivalent to the following:

(and) ≡ 't (and form ) ≡ form (and form 1 form 2 … form n ) ≡ (if form 1 (and form 2 … form n ) 'nil)

(and (= 2 2) (> 2 1)) ⇒ t (and (= 2 2) (< 2 1)) ⇒ nil (and (eql 'a 'a) (not (> 1 2))) ⇒ t (let ((x 'a)) (and x (setq x 'b))) ⇒ b (let ((x nil)) (and x (setq x 'b))) ⇒ nil (let ((time 10)) (if (and (< time 24) (> time 12)) (- time 12) time)) ⇒ 10 (let ((time 18)) (if (and (< time 24) (> time 12)) (- time 12) time)) ⇒ 6

( or form *) → object

or is the sequential logical or (or ∨ ). forms are evaluated from left to right until either one of them evaluates to a non-nil value or else none are left. If one of them evaluates to a non-nil value, then this non-nil value is returned, otherwise nil is returned. The form or is equivalent to the following:

(or) ≡ 'nil (or form ) ≡ form (or form 1 form 2 … form n ) ≡ ((lambda (var) (if var var (or form 2 … form n ))) form 1 ) where var does not occur in form 2 … form n

(or (= 2 2) (> 2 1)) ⇒ t (or (= 2 2) (< 2 1)) ⇒ t (let ((x 'a)) (or x (setq x 'b))) ⇒ a (let ((x nil)) (or x (setq x 'b))) ⇒ b

Control structure

Constants

constant → object

There are three kinds of constants: literals, quoted expressions, and named constants. Quoted expressions are described below.

The consequences are undefined if an attempt is made to alter the value of a constant.

The result of evaluating the literal constant constant is constant itself. Instances of the following classes are literal constants: basic-array, character, and number

#2A((a b c) (d e f)) ⇒ #2A((a b c) (d e f)) #\a ⇒ #\a 145932 ⇒ 145932 "abc" ⇒ "abc" #(a b c) ⇒ #(a b c)

( quote obj ) → object

' obj → object

A quoted expression denotes a reference to an object. This notation is used to include any object in an ISLISP text.

The character ' (apostrophe or single quote) is syntax for quotation. That is, (quote a) ≡ 'a.

The result of the evaluation of the quote special form is obj.

(quote a) ⇒ a (quote #(a b c)) ⇒ #(a b c) (quote (+ 1 2)) ⇒ (+ 1 2) '() ⇒ nil 'a ⇒ a '#(a b c) ⇒ #(a b c) '(car l) ⇒ (car l) '(+ 1 2) ⇒ (+ 1 2) '(quote a) ⇒ (quote a) ''a ⇒ (quote a) (car ''a) ⇒ quote

The consequences are undefined if an attempt is made to alter the value of a quoted expression.

Variables

Variable bindings are entities established during execution of the prepared variable-binding forms or by the activation of functions.

A variable is used to refer to an association between an identifier and an ISLISP object, and is denoted by that identifier. The association can be altered (by assignment) using the setf special form or setq special form.

The following are variable binding forms:

var → object

The value of var is the object associated with var in its variable binding.

(defglobal x 0) ⇒ x x ⇒ 0 (let ((x 1)) x) ⇒ 1 x ⇒ 0

( setq var form ) → object

This form represents an assignment to the variable denoted by the identifier. In consequence, the identifier may designate a different object than before, the value of form.

The result of the evaluation of form is returned. This result is used to modify the variable binding denoted by the identifier var (if it is mutable). setq can be used only for modifying bindings, and not for establishing a variable. The setq special form must be contained in the scope of var , established by defglobal, let, let*, for, or a lambda expression.

(defglobal x 2) ⇒ x (+ x 1) ⇒ 3 (setq x 4) ⇒ 4 (+ x 1) ⇒ 5 (let ((x 1)) (setq x 2) x) ⇒ 2 (+ x 1) ⇒ 5

( setf place form ) → object

This macro is used for generalized assignment.

setf takes a place and stores in this place the result of the evaluation of the form form. The place form is not evaluated as a whole entity, but subforms of place are evaluated sequentially from left to right to determine a place to be assigned a value. When place is denoted by an identifier, setf behaves exactly as setq. The returned value is the result of the evaluation of form. The valid places for the setf special form are as follows:

variables var dynamic bindings ( dynamic var ) the components of a basic-array ( aref basic-array z 1 … z n ) the components of a general array ( garef general-array z 1 … z n ) the components of a list ( elt list z ) the components of a vector ( elt basic-vector z ) the left component of a cons ( car cons ) the right component of a cons ( cdr cons ) a property of a symbol ( property symbol property ) a slot of an instance of a class ( reader-function-name instance )

A place can also be a macro form that expands (during preparation for execution) into a place or a function application form with operator op for which setf is defined or for which a generic function named (setf op) has been defined. In these last two cases, that function will receive as arguments the new value to be assigned followed by the objects that resulted from evaluating the arguments of the function application form.

(setf (car x) 2) ⇒ 2 In the cons x, the car now is 2. (defmacro first (spot) `(car ,spot)) ⇒ first (setf (first x) 2) ⇒ 2 In the cons x, the car now is 2.

( let (( var form )*) body-form *) → object

The let special form is used to define a scope for a group of identifiers for a sequence of forms body-form* (collectively referred to as the body). The list of pairs (var form)* is called the let variable list. The scope of the identifier var is the body.

The forms are evaluated sequentially from left to right; then each variable denoted by the identifier var is initialized to the corresponding value. Using these bindings along with the already existing bindings of visible identifiers the body-forms are evaluated. The returned value of let is the result of the evaluation of the last body-form of its body (or nil if there is none).

No var may appear more than once in let variable list.

Note: Although this form is a special form, one can think of it as a macro whose rewriting rules are as follows:

( let () body-form *) ≡ ( progn body-form *) ( let (( var 1 form 1 ) ( var 2 form 2 ) … ( var n form n )) body-form *) ≡ (( lambda ( var 1 var 2 … var n ) body-form * ) form 1 form 2 … form n )

(let ((x 2) (y 3)) (* x y)) ⇒ 6 (let ((x 2) (y 3)) (let ((x 7) (z (+ x y))) (* z x))) ⇒ 35 (let ((x 1) (y 2)) (let ((x y) (y x)) (list x y))) ⇒ (2 1)

( let* (( var form )*) body-form *) → object

The let* form is used to define a scope for a group of identifiers for a sequence of forms body-form* (collectively referred to as the body). The first subform (the let* variable list) is a list of pairs (var form). The scope of an identifier var is the body along with all form forms following the pair (var form) in the let* variable list.

For each pair (var form) the following is done: form is evaluated in the context of the bindings in effect at that point in the evaluation. The result of the evaluation is bound to its associated variable named by the identifier var. These variable bindings enlarge the set of current valid identifiers perhaps shadowing previous variable bindings (in case some var was defined outside), and in this enlarged or modified environment the body-forms are executed. The returned value of let* is the result of the evaluation of the last form of its body (or nil if there is none).

Note: Although this form is a special form, one can think of it as a macro whose rewriting rules are as follows:

( let* () body-form *) ≡ ( progn body-form *) ( let* (( var 1 form 1 ) ( var 2 form 2 ) … ( var n form n )) body-form *) ≡ ( let (( var 1 form 1 )) ( let (( var 2 form 2 )) … ( let (( var n form n )) body-form *)...))

(let ((x 2) (y 3)) (let* ((x 7) (z (+ x y))) (* z x))) ⇒ 70 (let ((x 1) (y 2)) (let* ((x y) (y x)) (list x y))) ⇒ (2 2)

Dynamic variables

A dynamic variable is an association between an identifier var and an ISLISP object in the dynamic variable namespace. Dynamic variables implement a form of dynamic binding.

Dynamic variables are defined globally by defdynamic and are established during the execution of a prepared dynamic-let.

Dynamic variable bindings defined by defdynamic persist indefinitely whereas those established by dynamic-let are disestablished upon end of execution of this special form.

The value of a dynamic variable can be accessed by (dynamic var).

( dynamic var ) → object

This special form denotes a reference to the identifier denoting a dynamic variable. This special form is not allowed in the scope of a definition of var which is not done by defdynamic or dynamic-let.

During activation, the current dynamic binding of the variable var is returned that was established most recently and is still in effect. An error shall be signaled if such a binding does not exist (error-id. unbound-variable).

( setf ( dynamic var ) form ) → object

( set-dynamic form var ) → object

This special form denotes an assignment to a dynamic variable. This form can appear anywhere that (dynamic var) can appear.

form is evaluated and the result of the evaluation is used to change the dynamic binding of var.

An error shall be signaled if var has no dynamic value (error-id. unbound-variable). setf of dynamic can be used only for modifying bindings, and not for establishing them.

( dynamic-let (( var form )*) body-form *) → object

The dynamic-let special form is used to establish dynamic variable bindings. The first subform (the dynamic-let variable list) is a list of pairs (var form). The scope of an identifier var defined by dynamic-let is the current toplevel scope. The extent of the bindings of each var is the extent of the body of the dynamic-let. The dynamic-let special form establishes dynamic variables for all vars.

References to a dynamic variable named by var must be made through the dynamic special form.

All the initializing forms are evaluated sequentially from left to right, and then the values are associated with the corresponding vars. Using these additional dynamic bindings and the already existing bindings of visible identifiers, the forms body-form* are evaluated in sequential order. The returned value of dynamic-let is that of the last body-form of the body (or nil if there is none). The bindings are undone when control leaves the prepared dynamic-let special form.

(defun foo (x) (dynamic-let ((y x)) (bar 1))) ⇒ foo (defun bar (x) (+ x (dynamic y))) ⇒ bar (foo 2) ⇒ 3

Conditional expressions

( if test-form then-form [ else-form ]) → object

The test-form is evaluated. If its result is anything non-nil, the then-form is evaluated and its value is returned; otherwise (if the test-form returned nil), the else-form is evaluated and its value is returned.

If no else-form is provided, it defaults to nil.

(if (> 3 2) 'yes 'no) ⇒ yes (if (> 2 3) 'yes 'no) ⇒ no (if (> 2 3) 'yes) ⇒ nil (if (> 3 2) (- 3 2) (+ 3 2)) ⇒ 1 (let ((x 7)) (if (< x 0) x (- x))) ⇒ -7

( cond ( test form *)*) → object

Executing the prepared cond, the clauses (test form*) are scanned sequentially and in each case the test is evaluated; when a test delivers a non-nil value the scanning process stops and all forms associated with the corresponding clause are sequentially evaluated and the value of the last one is returned. If no test is true, then nil is returned. If no form exists for the successful test then the value of this test is returned.

cond obeys the following equivalences:

( cond ) ≡ nil ( cond ( test 1 ) ( test 2 form 2 *) ...) ≡ ( or test 1 ( cond ( test 2 form 2 *) ...)) ( cond ( test 1 form 1 +) ( test 2 form 2 *) ...) ≡ ( if test 1 ( progn form 1 +) ( cond ( test 2 form 2 *) ...))

(cond ((> 3 2) 'greater) ((< 3 2) 'less)) ⇒ greater (cond ((> 3 3) 'greater) ((< 3 3) 'less)) ⇒ nil (cond ((> 3 3) 'greater) ((< 3 3) 'less) (t 'equal)) ⇒ equal

( case keyform (( key *) form *)* [( t form *)]) → object

( case-using predform keyform (( key *) form *)* [( t form *)]) → object

The case and case-using special forms, called case forms, provide a mechanism to execute a matching clause from a series of clauses based on the value of a dispatching form keyform.

The clause to be executed is identified by a set of keys. A key can be any object. If the keylist of the last clause is t the associated clause is executed if no key matches the keyform.

keyform is a form to be computed at the beginning of execution of the case form. If the result of evaluating keyform is equivalent to a key, then the forms, if any, in the corresponding clause are evaluated sequentially and the value of the last one is returned as value of the whole case form. case determines match equivalence by using eql; case-using match determines equivalence by using the result of evaluating predform. predform must be a boolean or quasi-boolean function that accepts two arguments, the value returned by keyform and key. If no form exists for a matching key, the case form evaluates to nil. If the value of keyform is different from every key, and there is a default clause, its forms, if any, are evaluated sequentially, and the value of the last one is the result of the case form.

The same key (as determined by the match predicate) may occur only once in a case form.

(case (* 2 3) ((2 3 5 7) 'prime) ((4 6 8 9) 'composite)) ⇒ composite (case (car '(c d)) ((a) 'a) ((b) 'b)) ⇒ nil (case (car '(c d)) ((a e i o u) 'vowel) ((y) 'semivowel) (t 'consonant)) ⇒ consonant (let ((char #\u)) (case char ((#\a #\e #\o #\u #\i) 'vowels) (t 'consonants))) ⇒ vowels (case-using #'= (+ 1.0 1.0) ((1) 'one) ((2) 'two) (t 'more)) ⇒ two (case-using #'string= "bar" (("foo") 1) (("bar") 2)) ⇒ 2

Sequencing forms

( progn form *) → object

This special form allows a series of forms to be evaluated, where normally only one could be used.

The result of evaluation of the last form of form* is returned. All the forms are evaluated from left to right. The values of all the forms but the last are discarded, so they are executed only for their side-effects. progn without forms returns nil.

(defglobal x 0) ⇒ x (progn (setq x 5) (+ x 1)) ⇒ 6 (progn (format (standard-output) "4 plus 1 equals ") (format (standard-output) "~D" (+ 4 1))) ⇒ nil prints 4 plus 1 equals 5

Iteration

( while test-form body-form *) → null

Iterates while the test-form returns a true value. Specifically:

test-form is evaluated, producing a value V t . If Vt is nil , then the while form immediately returns nil . Otherwise, if Vt is non-nil, the forms body-form * are evaluated sequentially (from left to right). Upon successful completion of the body-forms *, the while form begins again with step 1.

(let ((x '()) (i 5)) (while (> i 0) (setq x (cons i x)) (setq i (- i 1))) x) ⇒ (1 2 3 4 5)

( for ( iteration-spec *) ( end-test result* ) form *) → object

Where: iteration-spec ::= ( var init [ step ])

for repeatedly executes a sequence of forms form*, called its body. It specifies a set of identifiers naming variables that will be local to the for form, their initialization, and their update for each iteration. When a termination condition is met, the iteration exits with a specified result value.

The scope of an identifier var is the body, the steps, the end-test, and the result*. A step might be omitted, in which case the effect is the same as if (var init var) had been written instead of (var init). It is a violation if more than one iteration-spec names the same var in the same for form.

The for special form is executed as follows: The init forms are evaluated sequentially from left to right. Then each value is used as the initial value of the variable denoted by the corresponding identifier var, and the iteration phase begins.

Each iteration begins by evaluating end-test. If the result is nil, the forms in the body are evaluated sequentially (for side-effects). Afterwards, the step-forms are evaluated sequentially order from left to right. Then their values are assigned to the corresponding variables and the next iteration begins. If end-test returns a non-nil value, then the result* are evaluated sequentially and the value of the last one is returned as value of the whole for macro. If no result is present, then the value of the for macro is nil.

(for ((vec (vector 0 0 0 0 0)) (i 0 (+ i 1))) ((= i 5) vec) (setf (elt vec i) i)) ⇒ #(0 1 2 3 4) (let ((x '(1 3 5 7 9))) (for ((x x (cdr x)) (sum 0 (+ sum (car x)))) ((null x) sum))) ⇒ 25

Non-local exits

Establishing and invoking non-local exits

ISLISP defines three ways in which to perform non-local exits:

Destination Kind Established by Invoked by Operation Performed block name block return-from lexical exit tagbody tag tagbody go lexical transfer of control catch tag catch throw dynamic exit

A non-local exit, is an operation that forces transfer of control and possibly data from an invoking special form to a previously established point in a program, called the destination of the exit.

A lexical exit is a non-local exit from a return-from form to a block form which contains it both lexically and dynamically, forcing the block to return an object specified in the return-from form.

A dynamic exit is a non-local exit from a throw form to a catch form which contains it dynamically (but not necessarily lexically), forcing the catch to return an object specified in the throw form.

A lexical transfer of control is a non-local exit from a go form to a tagged point in a tagbody form which contains it both lexically and dynamically.

When a non-local exit is initiated, any potential destination that was established more recently than the destination to which control is being transferred is immediately considered invalid.

( block name form *) → object

( return-from name result-form

The block special form executes each form sequentially from left to right. If the last form exits normally, whatever it returns is returned by the block form.

The name in a block form is not evaluated; it must be an identifier. The scope of name is the body form*—only a return-from textually contained in some form can exit the block. The extent of name is dynamic.

If a return-from is executed, the result-form is evaluated. If this evaluation returns normally, the value it returns is immediately returned from the innermost lexically enclosing block form with the same name.

return-from is used to return from a block. name is not evaluated and must be an identifier. A block special form must lexically enclose the occurrence of return-from; the value produced by result-form is immediately returned from the block. The return-from form never returns and does not have a value.

An error shall be signaled if an attempt is made to exit a block after it has been exited (error-id. control-error); It is a violation if name is not an identifier. It is a violation if a block with a corresponding name does not exist. See §14.7.2 for other errors.

(block x (+ 10 (return-from x 6) 22)) ;;; Bad programming style ⇒ 6 (defun f1 () (block b (let ((f (lambda () (return-from b 'exit)))) … ; big computation (f2 f)))) ⇒ f1 (defun f2 (g) … ; big computation (funcall g)) ⇒ f2 (f1) ⇒ exit (block sum-block (for ((x '(1 a 2 3) (cdr x)) (sum 0 (+ sum (car x)))) ((null x) sum) (cond ((not (numberp (car x))) (return-from sum-block 0))))) ⇒ 0 (defun bar (x y) (let ((foo #'car)) (let ((result (block bl (setq foo (lambda () (return-from bl 'first-exit))) (if x (return-from bl 'second-exit) 'third-exit)))) (if y (funcall foo) nil) result))) ⇒ bar (bar t nil) ⇒ second-exit (bar nil nil) ⇒ third-exit (bar nil t) an error shall be signaled (bar t t) an error shall be signaled

( catch tag-form form *) → object

( throw tag-form result-form )

The special forms catch and throw provide a facility for programming of structured non-local dynamic exits. A catch form and a throw form are said to correspond if the tag-form of the catch and the tag-form of the throw evaluate to the same object, a catch tag. A catch tag may be any object other than a number or a character; the comparison of catch tags uses eq.

The catch special form first evaluates the tag-form to produce a catch tag, and then executes each form sequentially from left to right. If execution of the forms finishes normally, whatever is returned by the last form is returned by the catch form.

Prior to execution of the forms of a catch form C 0 , an association between the catch tag T 0 and the executing form C 0 is dynamically established, upon exit from C 0 , the association is disestablished. If there was an outer association for the same catch tag T 0 , it is hidden during the execution of C 0 's forms; only the most recently established (i.e., innermost) association for T 0 is ever visible.

If a throw special form is executed, it evaluates the tag-form producing a catch tag T 1 , and then evaluates the result-form producing a result R 1 . If there is a corresponding association between T 1 and some catch form C 1 that is executing, R 1 is immediately returned as the value of C 1 . The throw form can be anywhere in the entire current toplevel scope; it need not be lexically contained within C 1 .

An error shall be signaled if there is no outstanding catcher for a T 1 (error-id. control-error). See §14.7.2 for other errors.

(defun foo (x) (catch 'block-sum (bar x))) ⇒ foo (defun bar (x) (for ((l x (cdr l)) (sum 0 (+ sum (car l)))) ((null l) sum) (cond ((not (numberp (car l))) (throw 'block-sum 0))))) ⇒ bar (foo '(1 2 3 4)) ⇒ 10 (foo '(1 2 a 4)) ⇒ 0

( tagbody { tagbody-tag | form }*) → object

( go tagbody-tag )

tagbody executes the forms sequentially from left to right, discarding their values. If the execution of the last form completes normally, nil is returned by the tagbody special form.

The series of tagbody-tags and forms is collectively referred to as the body of a tagbody form. An identifier tagbody-tag that appears at toplevel of the body denotes a tagbody tag that can be used with go to transfer control to that point in the body. Any compound form that appears is taken as a form. Literals are not permitted at the toplevel of a tagbody. No tagbody-tag may appear more than once in the tags in the body.

The namespace used for tagbody tags is distinct from that used for block tags.

At any point lexically contained in the tagbody a form (go tag) can be used to transfer control to a tag tag that appears among the tagbody-tags, except where a tag is shadowed according to the lexical principle (see §11.1).

A tagbody-tag established by tagbody has lexical scope, but the point in the program to which it refers has dynamic extent. Once tagbody has been exited, it is no longer valid to use go to transfer to any tag in its body.

The determination of which elements of the body are tagbody-tags and which are forms is made prior to any macro expansion of that element. If form is a macro form and its macro expansion is a symbol or literal, that atom is treated as a form, not as a tagbody-tag.

It is a violation if a tagbody tag is other than an identifier. See §14.7.2 for other errors.

Note: As a stylistic matter, programmers are not encouraged to use tagbody and go in everyday programming. The primary uses for which these forms are intended are for implementing other control abstractions (using macros), and for the occassional real-world situation that uses unstructured imperative transfer of control (such as a finite state machine).

(defmacro with-retry (:rest forms) (let ((tag (gensym))) `(block ,tag (tagbody ,tag (return-from ,tag (flet ((retry () (go ,tag))) ,@forms)))))) ⇒ with-retry (let ((i -5)) (with-retry ;; if-error is a hypothetical error correction function ;; not supplied by ISLISP. (if-error (sqrt (setq i (+ i 4))) (retry)))) ⇒ 1.7320508075688772

Assuring data consistency during non-local exits

( unwind-protect form cleanup-form *) → object

unwind-protect first evaluates form. Evaluation of the cleanup-forms always occurs, regardless of whether the exit is normal or non-local.

If the form exits normally yielding a value R, then if all of the cleanup-forms exit normally the value R is returned by the unwind-protect form.

If a non-local exit from form occurs, then the cleanup-forms are executed as part of that exit, and then if all of the cleanup-forms exit normally the original non-local exit continues.

The cleanup-forms are evaluated from left to right, discarding the resulting values. If execution of the cleanup-forms finishes normally, exit from the unwind-protect form proceeds as described above. It is permissible for a cleanup-form to contain a non-local exit from the unwind-protect form, subject to the following constraint:

An error shall be signaled if during execution of the cleanup-forms of an unwind-protect form, a non-local exit is executed to a destination which has been marked as invalid due to some other non-local exit that is already in progress (see §14.7.1) (error-id. control-error).

Note: Because ISLISP does not specify an interactive debugger, it is unspecified whether or how error recovery can occur interactively if programmatic handling fails. The intent is that if the ISLISP processor does not terminate abnormally, normal mechanisms for non-local exit ( return-from , throw , or go ) would be used as necessary and would respect these cleanup-forms .

(defun foo (x) (catch 'duplicates (unwind-protect (bar x) (for ((l x (cdr l))) ((null l) 'unused) (remove-property (car l) 'label))))) ⇒ foo (defun bar (l) (cond ((and (symbolp l) (property l 'label)) (throw 'duplicates 'found)) ((symbolp l) (setf (property l 'label) t)) ((bar (car l)) (bar (cdr l))) (t nil))) ⇒ bar (foo '(a b c)) ⇒ t (property 'a 'label) ⇒ nil (foo '(a b a c)) ⇒ found (property 'a 'label) ⇒ nil (defun test () (catch 'outer (test2))) ⇒ test (defun test2 () (block inner (test3 (lambda () (return-from inner 7))))) ⇒ test2 (defun test3 (fun) (unwind-protect (test4) (funcall fun))) ⇒ test3 (defun test4 () (throw 'outer 6)) ⇒ test4 (test) ⇒ an error shall be signaled

In the test example, the throw executed in test4 has as destination the catcher established in test. The unwind-protect in test3 intercepts the transfer of control and attempts to execute a return-from from the block in test2. Because this block is established within the dynamic extent of the destination catcher, an error is signaled.

Objects

Defining classes

The defclass defining form is used to define a new named class.

The definition of a class includes the following:

The name of the new class.

The list of the direct superclasses of the new class.

A set of slot specifiers . Each slot specifier includes the name of the slot and zero or more slot options . A slot option pertains only to a single slot. A class definition must not contain two slot specifiers with the same name.

. Each slot specifier includes the name of the slot and zero or more . A slot option pertains only to a single slot. A class definition must not contain two slot specifiers with the same name. A set of class options . Each class option pertains to the class as a whole.

The slot options and class options of the defclass defining form provide mechanisms for the following:

Supplying a default initial value form for a given slot.

Requesting that methods for generic functions be automatically generated for retrieving or storing slot values and inquiring whether a value is bound to the slot.

Indicating that the metaclass of that class is to be other than the default.

( defclass class-name ( sc-name *) ( slot-spec *) class-opt *) → symbol

Where: class-name ::= identifier sc-name ::= identifier slot-spec ::= slot-name | ( slot-name slot-opt *) slot-name ::= identifier slot-opt ::= :reader reader-function-name | :writer writer-function-name | :accessor reader-function-name | :boundp boundp-function-name | :initform form | :initarg initarg-name initarg-name ::= identifier reader-function-name ::= identifier writer-function-name ::= identifier boundp-function-name ::= identifier class-opt ::= ( :metaclass class-name ) | ( :abstractp abstract-flag ) abstract-flag ::= t | nil

The defclass defining form returns the symbol named class-name as its result.

The class-name argument is an identifier which becomes the name of the new class. The defining point of the class-name is the end of the defclass defining form.

Each superclass name argument sc-name is an identifier that specifies a direct superclass of the new class. The new class will inherit slots and their :reader or :writer or :accessor methods from each of its superclasses. See §15.1.3 for a definition of how slots are inherited, and §15.2.3 for a definition of how methods are inherited. No sc-name may appear more than once in super class names. It is a violation if the superclasses of any two direct superclasses sc-name have superclasses other than standard-object and object in common unless a metaclass other than standard-class is specified.

Each slot-spec argument is the name of the slot or a list consisting of the slot name followed by zero or more slot options. The slot-name argument is an identifier that is syntactically valid for use as an ISLISP variable name. No slot names may appear more than once in slot-spec The following slot options are available:

The :reader slot option specifies that an unqualified method with the parameter profile (( x class-name )) is to be defined on the generic function named reader-function-name to retrieve the value of the given slot. The :reader slot option may be specified more than once for a given slot.

slot option specifies that an unqualified method with the parameter profile (( )) is to be defined on the generic function named to retrieve the value of the given slot. The slot option may be specified more than once for a given slot. The :writer slot option specifies that an unqualified method with the parameter profile (( y object ) ( x class-name )) is to be defined on the generic function named writer-function-name to store the value into the slot. The writer-function-name argument is an identifier. The :writer slot option may be specified more than once for a given slot.

slot option specifies that an unqualified method with the parameter profile (( ) ( )) is to be defined on the generic function named to store the value into the slot. The argument is an identifier. The slot option may be specified more than once for a given slot. The :accessor slot option specifies that an unqualified method is to be defined on the generic function named reader-function-name to retrieve the value of the given slot. Furthermore, there is a generic function such that ( setf ( reader-function-name x ) y ) is equivalent to calling this generic function with first argument y and second argument x . This generic function is extended by a method with the parameter profile (( y object ) ( x class-name )). The reader-function-name argument is an identifier. The :accessor slot option may be specified more than once for a given slot.

slot option specifies that an unqualified method is to be defined on the generic function named to retrieve the value of the given slot. Furthermore, there is a generic function such that ( ( ) ) is equivalent to calling this generic function with first argument and second argument . This generic function is extended by a method with the parameter profile (( ) ( )). The argument is an identifier. The slot option may be specified more than once for a given slot. The :boundp slot option specifies that an unqualified method with the parameter profile (( x class-name )) is to be defined on the generic function named boundp-function-name to test whether the given slot has been given a value. The :boundp slot option may be specified more than once for a given slot.

slot option specifies that an unqualified method with the parameter profile (( )) is to be defined on the generic function named to test whether the given slot has been given a value. The slot option may be specified more than once for a given slot. The :initform slot option is used to provide a default initial value form to be used in the initialization of the slot. The :initform slot option may be specified once at most for a given slot. This form is evaluated every time it is used to initialize the slot. The lexical scope of the identifiers used in the initialization of the slot is the lexical scope of those identifiers in the defclass form. Note that the lexical scope refers both to variable and to function identifiers. In contrast, the current dynamic bindings used are those existing during activation of create. For more information, see §15.4.1.

slot option is used to provide a default initial value form to be used in the initialization of the slot. The slot option may be specified once at most for a given slot. This form is evaluated every time it is used to initialize the slot. The lexical scope of the identifiers used in the initialization of the slot is the lexical scope of those identifiers in the defclass form. Note that the lexical scope refers both to variable and to function identifiers. In contrast, the current dynamic bindings used are those existing during activation of create. For more information, see §15.4.1. The :initarg slot option declares an initialization argument named initarg-name and specifies that this initialization argument initializes the given slot. If the initialization argument and associated value are supplied in the call to initialize-object , the value will be stored into the given slot and the slot's :initform slot option, if any, is not evaluated. If none of the initialization arguments specified for a given slot has a value, the slot is initialized according to the :initform option, if specified. The consequences are undefined if more than one initialization argument for the same slot is supplied. For more information, see §15.4.1.

The generic functions, to which the methods created by the :reader, :writer, and :accessor slot options belong are called slot accessors.

No implementation is permitted to extend the syntax of defclass to allow (slot-name form) as an abbreviation for (slot-name :initform form).

Each class option is an option that refers to the class as a whole. The following class options are available:

The :metaclass class option is used to specify that instances of the class being defined are to have a different metaclass than the default provided by the system, that is, different from the class standard-class . The class-name argument is the name of the desired metaclass. The :metaclass class option may be specified once at most. It is a violation if built-in-class is specified as the metaclass.

class option is used to specify that instances of the class being defined are to have a different metaclass than the default provided by the system, that is, different from the class . The argument is the name of the desired metaclass. The class option may be specified once at most. It is a violation if is specified as the metaclass. The :abstractp class option is used to specify that the class is an abstract class. If this option is supplied and abstract-flag is t , create will signal an error if an attempt is made to create an instance of this class. If the option is unsupplied, or if abstract-flag is nil , the class is not an abstract class. It is a violation if the abstract-flag is supplied but is neither t nor nil .

The following rules of defclass hold for standard classes:

The defclass defining form must be in the scope of any superclass identifier it refers to.

defining form must be in the scope of any superclass identifier it refers to. All the superclasses of a class must be defined before an instance of the class can be made.

Any reference to class-name as a parameter specializer in a defmethod form must be in the scope of class-name. That is, a defmethod form that names a class must textually follow the defclass form that defines that class.

An ISLISP processor may be extended to cover situations where these rules are not obeyed. These extensions shall be implementation defined.

Some slot options are inherited by a class from its superclasses, and some can be shadowed or altered by providing a local slot description. No class options are inherited. For a detailed description of how slots and slot options are inherited, see the section §15.1.3.

If no slot accessors are specified for a slot, the slot cannot be accessed.

When a class is defined, the order in which its direct superclasses are mentioned in the defining form is important. The new class has a local precedence order, which is a list consisting of the class followed by its direct superclasses in the order mentioned in its defclass defining form.

Determining the class precedence list

The defclass defining form for a class provides a total ordering on that class and its direct superclasses. This ordering is called the local precedence order. It is an ordered list of the class and its direct superclasses. The class precedence list for a class C is a total ordering on C and its superclasses that is consistent with the local precedence orders for each of C and its superclasses.

The class precedence list is always consistent with the local precedence order of each class in the list. The classes in each local precedence order appear within the class precedence list in the same order.

Let C 1 , … , C n be the direct superclasses of C in the order defined in the defclass defining form for C. Let P 1 , … , P n be the class precedence lists for C 1 , … , C n , respectively. Define P · Q on class precedence lists P and Q to be the two lists appended. Then the class precedence list for C is C · P 1 · … · P n with duplicate classes removed by repeated application of the following rule: If a class appears twice in the resulting class precedence list, the leftmost occurrence is removed.

It is a violation if an attempt is made to define an instance of standard-class whose direct superclasses have class precedence lists with classes other than standard-object and object in common.

Accessing slots

Slots can be accessed by use of the slot accessors created or modified by the defclass defining form.

The defclass defining form provides syntax for generating methods to retrieve and store slot values. If a reader is requested, a me