Objects

In EuLisp, every object in the system has a specific class. Classes themselves are first-class objects. In this respect EuLisp differs from statically-typed object-oriented languages such as C++ and microCEYX. The EuLisp object system is called Telos. The facilities of the object system are split across the two levels of the definition. Level-0 supports the definition of generic functions, methods and structures. The defined name of this module is telos0.

Programs written using Telos typically involve the design of a class hierarchy, where each class represents a category of entities in the problem domain, and a protocol, which defines the operations on the objects in the problem domain.

A class defines the structure and behaviour of its instances. Structure is the information contained in the class's instances and behaviour is the way in which the instances are treated by the protocol defined for them.

The components of an object are called its slots. Each slot of an object is defined by its class.

A protocol defines the operations which can be applied to instances of a set of classes. This protocol is typically defined in terms of a set of generic functions, which are functions whose application behaviour depends on the classes of the arguments. The particular class-specific behaviour is partitioned into separate units called methods. A method is not a function itself, but is a closed expression which is a component of a generic function.

Generic functions replace the send construct found in many object-oriented languages. In contrast to sending a message to a particular object, which it must know how to handle, the method executed by a generic function is determined by all of its arguments. Methods which specialize on more than one of their arguments are called multi-methods.

Inheritance is provided through classes. Slots and methods defined for a class will also be defined for its subclasses but a subclass may specialize them. In practice, this means that an instance of a class will contain all the slots defined directly in the class as well as all of those defined in the class's superclasses. In addition, a method specialized on a particular class will be applicable to direct and indirect instances of this class. The inheritance rules, the applicability of methods and the generic dispatch are described in detail later in this section.

Classes are defined using the defclass () and defcondition (?? ) defining forms, both of which create top-lexical bindings.

Generic functions are defined using the defgeneric defining form, which creates a named generic function in the top-lexical environment of the module in which it appears and generic-lambda, which creates an anonymous generic function. These forms are described in detail later in this section.

Methods can either be defined at the same time as the generic function, or else defined separately using the defmethod macro, which adds a new method to an existing generic function. This macro is described in detail later in this section.

System Defined Classes

The basic classes of EuLisp are elements of the object system class hierarchy, which is shown in Figure ?? . Indentation indicates a subclass relationship to the class under which the line has been indented, for example, <condition> is a subclass of <object>. The names given here correspond to the bindings of names to classes as they are exported from the level-0 modules. Classes directly relevant to the object system are described in this section while others are described in corresponding sections, e.g. <condition> is described in Section ?? . - abstract - abstract - concrete - abstract - abstract - concrete - concrete - abstract - abstract - abstract - concrete - abstract - concrete - concrete - concrete - abstract - concrete - abstract - abstract - concrete - abstract - concrete - concrete - abstract - abstract - concrete - abstract - concrete - concrete - abstract - abstract - concrete - abstract - concrete - abstract - concrete - abstract - abstract - concrete - concrete - abstract - concrete In this definition, unless otherwise specified, classes declared to be subclasses of other classes may be indirect subclasses. Classes not declared to be in a subclass relationship are disjoint. Furthermore, unless otherwise specified, all objects declared to be of a certain class may be indirect instances of that class.


<object> : class
The root of the inheritance hierarchy. <object> defines the basic methods for initialization and external representation of objects. No initialization options are specified for <object>.


<class> : class
The default superclass of classes. All classes defined using the defclass form are direct or indirect subclasses of <class>. Thus, this class is specializable by user-defined classes at level-0.


<generic- function-condition> : <condition>
This is the general condition class for conditions arising from operations in the object system at level 0. The following direct subclasses of <generic-function-condition> are defined at level 0:
  • <no-applicable-method>, signalled by a generic function when there is no method which is applicable to the arguments.
  • <incompatible-method-domain>, signalled by if the domain of the method being added to a generic function is not a subdomain of the generic function's domain.
  • <non-congruent-lambda-lists>, signalled if the lambda list of the method being added to a generic function is not congruent to that of the generic function.
  • <method-domain-clash>, signalled if the method being added to a generic function has the same domain as a method already attached to the generic function.
  • <no-next-method>, signalled by call-next-method if there is no next most specific method.

Single Inheritance

Telos level-0 provides only single inheritance, meaning that a class can have exactly one direct superclass|but indefinitely many direct subclasses. In fact, all classes in the level-0 class inheritance tree have exactly one direct superclass except the root class <object> which has no direct superclass. Each class has a class precedence list (CPL), a linearized list of all its superclasses, which defines the classes from which the class inherits structure and behaviour. For single inheritance classes, this list is defined recursively as follows:
  1. the CPL of <object> is a list of one element containing <object> itself;
  2. the CPL of any other class is a list of classes beginning with the class itself followed by the elements of the CPL of its direct superclass which is <object> by default.
The class precedence list controls system-defined protocols concerning:
  1. inheritance of slot and class options when initializing a class;
  2. method lookup and generic dispatch when applying a generic function.

Defining Classes


defclass : defining form

Syntax

defclass form = '(', 'defclass', class name, superclass name, slot list, {class option}, ')'; class name = identifier; (* ?? *) superclass name = identifier; (* ?? *) slot list = '(', {slot}, ')'; slot = slot name | '(', slot name, {slot option}, ')'; slot name = identifier; (* ?? *) slot option = 'keyword:' keyword (* ?? *) | 'default:' level 0 expression (* ?? *) | 'reader:' identifier (* ?? *) | 'writer:' identifier (* ?? *) | 'accessor:' identifier (* ?? *) | 'requiredp:' boolean; class option = 'keywords:', '(', {identifier}, ')' | 'constructor:', constructor specification | 'predicate:' identifier (* ?? *) | 'abstractp:' boolean; constructor specification = identifier | '(', identifier, {keyword name}, ')'

Arguments

class name
A symbol naming a binding to be initialized with the new structure class. The binding is immutable.
superclass name
A symbol naming a binding of a class to be used as the direct superclass of the new structure class.
slot list
A list of slots (see below), comprising either a slot name or a list of a slot name followed by some slot options.
class option
A key and a value (see below) which, taken together, apply to the class as a whole.

Remarks

codedefclass defines a new structure class. Structure classes support single inheritance as described above. Neither class redefinition nor changing the class of an instance is supported by structure classes (Note 1: In combination with the guarantee that the behaviour of generic functions cannot be modified once it has been defined, due to no support for method removal nor method combination, this imbues level-0 programs with static semantics.). The slot options are interpreted as follows:
keyword : keyword
The value of this option is a keyword, which is the name of an argument to be supplied in the initialization options of a call to make on the new class. The value of this argument in the call to make is the initial value of the slot. This option must only be specified once for a particular slot. The same keyword may be used for several slots, in which case they will share the same initial value if the keyword is given to make. Subclasses inherit the keyword. Each slot must have at most one keyword including the inherited one. That means a subclass cannot shadow or add a new keyword if a superclass has already defined one.
default : expression
The value of this option is an expression, which is evaluated as the default value of the slot, to be used if no keyword is defined for the slot or given to a call to make. The expression is evaluated in the lexical environment of the call to defclass and the dynamic environment of the call to make. The expression is evaluated each time make is called and the default value is required. The order of evaluation of the default expressions in all the slots is determined by initialize. This option must only be specified once for a particular slot. Subclasses inherit the default. However, a more specific form may be specified in a subclass, which will shadow the inherited one.
reader : identifier
The value is the identifier of the variable to which the reader function will be bound. The binding is immutable. The reader function is a means to access the slot. The reader function is a function of one argument, which should be an instance of the new class. No writer function is automatically bound with this option. This option can be specified more than once for a slot, creating several bindings for the same reader function. It is a static error to specify the same reader, writer, or accessor name for two different slots.
writer : identifier
The value is the identifier of the variable to which the writer function will be bound. The binding is immutable. The writer function is a means to change the slot value. The creation of the writer is analogous to that of the reader function. The writer function is a function of two arguments, the first should be an instance of the new class and the second can be any new value for the slot. This option can be specified more than once for a slot. It is a static error to specify the same reader, writer, or accessor name for two different slots.
accessor : identifier
The value is the identifier of the variable to which the reader function will be bound. In addition, the use of this slot option causes the writer function to be associated to the reader via the setter mechanism. This option can be specified more than once for a slot. It is a static error to specify the same reader, writer, or accessor name for two different slots.
requiredp : boolean
The value is either true or false. True indicates that an initialization argument must be supplied for this slot.
The class options are interpreted as follows:
keywords : list
The value of this option is a list of keywords which extend the inherited names of arguments to be supplied in the init-options of a call to make on the new class. Keywords are inherited by union. The values of all legal arguments in the call to make are the initial values of corresponding slots if they name a slot keyword or are ignored by the default initialize method, otherwise. This option must only be specified once for a class.
constructor : constructor specification
Creates a constructor function for the new class. The constructor specification comes in two forms. The first names an identifier to which the constructor function will be bound. This constructor function takes no arguments and returns an instance in which the slots have been filled in according to the default values. The second form of the constructor specification gives the name to which the constructor function will be bound, followed by a sequence of legal keywords for the class. This constructor function takes a number of arguments corresponding to the number of keywords given in the constructor specification. It creates an instance of the class and fills in the slots according to the match between the specified keywords and the given arguments to the constructor function. The construtor option may be specified any number of times for a class.
predicate : identifier
Creates a function which tests whether an object is an instance of the new class. The predicate specification gives the name to which the predicate function will be bound. This option may be specified any number of times for a class.
abstractp : boolean
The value is either true or false. True indicates that the class being defined is abstract.


abstract-class-p : function

Arguments

object
Returns object, if it is an abstract class, otherwise ().

Julian Padget, jap@maths.bath.ac.uk, this version February 27, 1995