A class may list any number of superclasses. If none are listed, the class is taken to be a subclass of Any. Any is the root of the class system. It defines only the fixed slot self, providing a reference to self. Subclass declarations extend the scopes of their superclasses. The declared class structure determines the type structure for links. The type of a link referencing instances of a class is a subtype of superclass link types.
Subclass declarations extend those of their superclasses. All stated properties (slot definitions and constraints) in superclasses are preserved in subclasses. Additions may not invalidate superclass properties. Detected conflicts may be trapped as programming errors by a translator, but it is not specified whether or how conformance is enforced.
Subclass declarations take two forms, adding new slots and adding (strengthening) features to those listed in superclasses. Additions are conjoined to the corresponding superclass declarations. Full redeclarations are unnecessary except in those cases where features cannot otherwise be expressed (e.g., when adding qualifiers). When a new slot has the same name as one in the superclass, or when two or more superclasses have slots of the same name, the following rules apply:
The first two cases are instances of adding features to existing slots. The following additions are permitted. Analogous rules apply when merging the declarations of two or more superclasses.
These rules apply whenever a subclass adds a new version of a slot or two superclass versions exist. All declarations of different versions are interpreted as if they were different arms of a single operation with multiple when guards. A translator may fabricate guards (and/or perform equivalent transformations) in any way consistent with the declarations. For example, in:
class A ... end class B is A ... end class C ... end; class D op m(a: A) ==> ea end; op m(b: B) ==> eb end; op m(c: C) ==> ec end; end
The declarations of m in D may be transformed into a single operation, with all argument types recast in terms of their nearest common superclasses (here, just Any):
op m(x: Any) when x in B ==> eb elsewhen x in A ==> ea elsewhen x in C ==> ec else pend end
The implicit negation of preceding guards in when clauses transforms consistency issues to ordering issues in the equivalent ODL code. For example, this may also be transformed as:
op m(x: Any) when x in C ==> ec elsewhen x in B ==> eb elsewhen x in A ==> ea else pend end
In both cases, the version for B specializes that for A. However, class C bears no subclass or superclass relation to the others, so the clause may be considered in either fashion, at the discretion of the translator. For example, if the operation were invoked with an argument of type AC (a subclass of both A and C) then either version might trigger. While not disallowed, such non-determinism should be avoided.
The results of different versions of procedural operations may also vary. The combination rules are the same as would apply if each reply were considered as an operation proper. The base version is constructed by conjoining all cases as multiple replies, while merging (as the nearest common superclass) the types of identically named (or nameless) replies in those cases where fields differ only in link type. For example:
class E op p(a: A) f: A ; op p(b: B) g: B ; op p(c: C) h: int; op p(d: D) ok(), bad(i: int) endThis may be represented in the form:
class E op p(a: Any) fg: A, h: int, ok(), bad(i: int); endWhen a superclass version of the procedure exists, the resulting return expression must conform. In particular, added named reply forms resulting from such combinations are not allowed.
A constraint of the form C = oneOf(S1, S2, ... Sn) limits the declarable subclasses of C to those listed under OneOf. Stylistically, OneOf is used to indicate that the listed subclasses are the only ones logically possible. For example, a class with a fixed bool slot might be partitioned into two subclasses with it set to true versus false. Also, subclasses defined via OneOf serve as analogs of enumeration types found in other languages. A translator may enforce and exploit the facts that partitioning constraints place fixed bounds on the number of subclasses and/or that partitioned siblings may never have a common subclass.
A class may list another ``base'' class in an opens clause to indicate that it shares all but specifically redeclared features with this base. The rules are the same as those under normal inheritance except that any feature may be redeclared in any way -- declarative constraints in the base declaration are ignored. Additionally, any unguarded base slot may be redeclared as local. The class listed in opens is not a superclass; link types of the derived class are not subtypes of those for the base.