5 Types and Classes

Every object is a **direct instance** of exactly one class, and a general instance of the **general superclasses** of that class.

A class determines which slots its instances have. Slots are the local storage available within instances. They are used to store the state of objects.

Classes determine how their instances are initialized by using the **initialization protocol**.

- A class can be
**abstract**or**concrete**. If the class is concrete, it can have direct instances. If it is abstract, it cannot have direct instances, but only indirect instances. - A class can be
**instantiable**or**uninstantiable**. If the class is instantiable, it can be used as the first argument to`make`

. If it is uninstantiable, it cannot be used as the first argument to`make`

. - A class can be
**primary**or**free**. This controls how a class can be used for multiple inheritance. For a full description of this feature, see "Declaring Characteristics of Classes" on page 132. - A class can be
**sealed**or**open**. This controls whether a class can be subclassed outside the library where it is defined. For a full description of this feature, see "Declaring Characteristics of Classes" on page 132.

`make`

on `<class>`

, or with the definition define class. In most programs the latter is more commonly used.
When a class is created with `make`

, it is instantiated and returned just like any other object. The options available when creating a class with `make`

are described on page 184.

When a class is created with `define class`

it is used to initialize a new module binding. `define class`

allows the specification of superclasses, slots, initialization behavior, and options related to sealing. The complete syntax of `define class`

is given on page 364.

The following simple class definition creates a class named by the module binding `<new>`

. The class inherits from `<object>`

, and does not specify any slots.

define class <new> (<object>) end class <new>;The following class definition illustrates the creation of a class with multiple superclasses. Again, there are no slots.

define class <color-window> (<palette>, <window>) end class <color-window>;

The subclass relationship is transitive. If a class *C* is a direct subclass of *C 1*,

Inheritance cannot be circular. A class cannot be its own general subclass.

A class is a subtype of each of its general superclasses.

Every class is a general subclass of `<object>`

.

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 of each of *C* and its superclasses as well as with the ordering in the class precedence list of each of its superclasses.

Sometimes there are several possible total orderings on *C* and its superclasses that are consistent with the local precedence orders for each of *C* and its superclasses. Dylan uses a deterministic algorithm to compute the class precedence list, which chooses one of the possible total orderings.

Sometimes there is no possible total ordering on *C* and its superclasses that is consistent with the local precedence orders for each of *C* and its superclasses. In this case, the class precedence list cannot be computed, and an error is signaled.

To compute the class precedence list for class *C*:

- Let
*S*be the set of class*C*and all of its superclasses. - Let
*C*...*1**C*be the members of*n**S*. - Let
*D*...*1**D*be the direct superclasses of*m**C*. - Let
*L*be the class precedence list of*C*. - Let
*CPL*...*1**CPL*be, respectively, the class precedence lists of*m**D*...*1**D*.*m* - A class
*C*is said to*1***precede**class*C*if*2**C*must appear before*1**C*in*2**L*. - To compute
*L*, pick a class*N*in*S*such that there are no classes in*S*that precede*N*. If there is no such class, the class*C*is inconsistent and its creation is not permitted. - If there are several classes from
*S*with no predecessors, select the one that has a direct subclass rightmost in the partial class precedence list computed so far. (In more precise terms, let {*N*,...*1**N*},*m**m*>=2, be the classes from*S*with no predecessors. Let (*C*,...,*1**C*),*n**n*>=1, be the partial class precedence list computed so far.*C*is the most specific class, and*1**C*is the least specific. Let 1<=*n**j*<=*n*be the largest number such that there exists an*i*where 1<=*i*<=*m*and*N*is a direct superclass of*i**C*. Select*j**N*as*i**N*.) - Remove
*N*from*S*. Add*N*to the end of*L*. Continue adding classes from*S*to*L*, as above, until*S*is empty.This algorithm can be implemented with the following Dylan program:

`define method compute-all-superclasses (c :: <class>) let local-precedence-order-constraints = add!(compute-constraints(c.direct-superclasses), list(c, first(c.direct-superclasses))); let monotonicity-constraints = reduce1(concatenate, map(compose(compute-constraints, all-superclasses), c.direct-superclasses)); let constraints = remove-duplicates(concatenate(local-precedence-order-constraints, monotonicity-constraints), test: \=); let all-supers = reduce(union, list(c), map(all-superclasses, c.direct-superclasses)); topological-sort(all-supers, constraints, tie-breaker-rule) end method compute-all-superclasses;`

`// Given an ordered list, pair up adjacent elements to give the // constraint set for the ordering.`

`define method compute-constraints (l :: <list>) if (empty?(l) | empty?(l.tail)) #() else pair(list(l.first, l.second), compute-constraints(l.tail)) end end method compute-constraints;`

`define method topological-sort (elements :: <list>, constraints :: <list>, tie-breaker :: <function>) local method sort (remaining-constraints, remaining-elements, result) local method next-minimal-elements (remaining-elements :: <list>) choose(method (class) ~member?(class, remaining-constraints, test: method (a, b) a == b.second end method) end method, remaining-elements) end method next-minimal-elements; let minimal-elements = next-minimal-elements(remaining-elements); if (empty?(minimal-elements)) if (empty?(remaining-elements)) result else error("Inconsistent precedence graph ~S.", remaining-elements) end if else let choice = if (empty?(minimal-elements.tail)) minimal-elements.head else tie-breaker(minimal-elements, result) end if; sort(remove(remaining-constraints, choice, test: method (a, b) member?(b, a) end), remove(remaining-elements, choice), concatenate(result, list(choice))) end if end method sort; sort(constraints, elements, #()) end method topological-sort;`

`define method tie-breaker-rule (minimal-elements, cpl-so-far) block (return) for (cpl-constituent in cpl-so-far.reverse) let supers = cpl-constituent.direct-superclasses; let common = intersection(minimal-elements, supers); unless (empty?(common)) return(common.head) end unless; end for end block end method tie-breaker-rule;`

Dylan Reference Manual - 17 OCT 1995 [Next] [Previous] [Up] [Top] [Contents] [Index]

Generated with Harlequin WebMaker