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.
make
. If it is uninstantiable, it cannot be used as the first argument to make
.
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 C1, C1 is a direct subclass of C2, and C2 is a direct subclass of C3, then C is an indirect subclass of C2 and C3. A general subclass is a direct or indirect subclass.
Inheritance cannot be circular. A class cannot be its own general subclass.
A class is a subtype of each of its general superclasses.
Every class is a general subclass of <object>
.
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:
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;
Generated with Harlequin WebMaker