Function
Returns a type representing a class and its subclasses.
subclass class => subclass-type
<class>.
<type>.
common-extensions
common-extensions
Returns a type that describes all the objects representing subclasses of the given class. We term such a type a subclass type.
The subclass function is allowed to return an existing type if that type is type equivalent to the subclass type requested.
Without subclass, methods on generic functions (such as Dylan's standard make and as) that take types as arguments are impossible to reuse without resorting to ad hoc techniques. In the language defined by the DRM, the only mechanism available for specializing such methods is to use singleton types. A singleton type specializer used in this way, by definition, gives a method applicable to exactly one type. In particular, such methods are not applicable to subtypes of the type in question. In order to define reusable methods on generic functions like this, we need a type which allows us to express applicability to a type and all its subtypes.
For an object O and class Y, the following instance? relationship applies:
INSTANCE-1: instance?(O, subclass(Y))
True if and only if O is a class and O is a subclass of Y.
For classes X and Y the following subtype? relationships hold (note that a rule applies only when no preceding rule matches):
SUBTYPE-1: subtype?(subclass(X), subclass(Y))
True if and only if X is a subclass of Y.
SUBTYPE-2: subtype?(singleton(X), subclass(Y))
True if and only if X is a class and X is a subclass of Y.
SUBTYPE-3: subtype?(subclass(X), singleton(Y))
Always false.
SUBTYPE-4: subtype?(subclass(X), Y)
where Y is not a subclass type. True if Y is <class> or any proper superclass of <class> (including <object>, any implementation-defined supertypes, and unions involving any of these). There may be other implementation-defined combinations of types X and Y for which this is also true.
SUBTYPE-5: subtype?(X, subclass(Y))
where X is not a subclass type. True if Y is <object> or any proper supertype of <object> and X is a subclass of <class>.
Note that by subclass relationships SUBTYPE-4 and SUBTYPE-5, we get this correspondence: <class> and subclass(<object>) are type equivalent.
Where the subtype? test has not been sufficient to determine an ordering for a method's argument position, the following further method-ordering rules apply to cases involving subclass types (note that a rule applies only when no preceding rule matches):
SPECIFICITY+1. subclass(X) precedes subclass(Y) when the argument is a class C and X precedes Y in the class precedence list of C.
SPECIFICITY+2. subclass(X) always precedes Y, Y not a subclass type. That is, applicable subclass types precede any other applicable class-describing specializer.
The constraints implied by sealing come by direct application of sealing rules 1-3 (see page 136of the DRM) and the following disjointness criteria for subclass types (note that a rule applies only when no preceding rule matches):
DISJOINTNESS+1. A subclass type subclass(X) and a type Y are disjoint if Y is disjoint from <class>, or if Y is a subclass of <class> without instance classes that are also subclasses of X.
DISJOINTNESS+2. Two subclass types subclass(X) and subclass(Y) are disjoint if the classes X and Y are disjoint.
DISJOINTNESS+3. A subclass type subclass(X) and a singleton type singleton(O) are disjoint unless O is a class and O is a subclass of X.
The guiding principle behind the semantics is that, as far as possible, methods on classes called with an instance should behave isomorphically to corresponding methods on corresponding subclass types called with the class of that instance. So, for example, given the heterarchy:
<object>
|
<A>
/ \
<B> <C>
\ /
<D>and methods:
method foo (<A>) method foo (<B>) method foo (<C>) method foo (<D>)
method foo-using-type (subclass(<A>)) method foo-using-type (subclass(<B>)) method foo-using-type (subclass(<C>)) method foo-using-type (subclass(<D>))
that for a direct instance D1 of <D>:
foo-using-type(<D>)
should behave analogously to:
foo(D1)
with respect to method selection.
define class <A> (<object>) end; define class <B> (<A>) end; define class <C> (<A>) end; define class <D> (<B>, <C>) end;
define method make (class :: subclass(<A>), #key)
print("Making an <A>");
next-method();
end method;define method make (class :: subclass(<B>), #key)
print("Making a <B>");
next-method();
end method;define method make (class :: subclass(<C>), #key)
print("Making a <C>");
next-method();
end method;define method make (class :: subclass(<D>), #key)
print("Making a <D>");
next-method();
end method;? make(<D>);
Making a <D>
Making a <B>
Making a <C>
Making an <A>
{instance of <D>}