(* Copyright (C) 1992, Digital Equipment Corporation *) (* All rights reserved. *) (* See the file COPYRIGHT for a full description. *) (* *) (* Last modified on Sun Aug 9 19:01:27 1992 by meehan *) (* modified on Tue Jun 16 13:08:35 PDT 1992 by muller *) (* modified on Sat Jun 13 09:40:58 1992 by mhb *) (* A {\em multi} is a "VBT" to which a set of methods has been added ("replace", "insert", "pred", etc.) to provide flexibility in the organization of ``logical'' children, so that it need not be constrained to be a subtype of "VBT.Filter" or "VBT.Split" and follow the rules for ``"VBT"-children''. In a language with multiple inheritance, multis would simply inherit different methods from different parent-types. In Modula-3, however, we achieve this affect by creating an instance "mc" of type "MultiClass.T", and attaching "mc" to a "VBT" "v" by way of "v"'s property set. "mc" points back to "v" via the field "mc.vbt". Clients that are defining their own multis can make a "VBT" "v" ``into'' a multi by calling "Be(v, mc)" during initialization. They should also call "BeChild" on each new child when it is inserted, and "UnChild" when a child of a multi is deleted. "Multi.Replace" calls "BeChild" automatically. Some clients export their multiclass, e.g., "BooleanVBT.MC", and their "init" methods take a multiclass argument which defaults to "NIL". By convention, this means that the "init" method will use a new instance of the exported multiclass, e.g., "NEW(MC)", as the multiclass. *) INTERFACE MultiClass; IMPORT List, Multi, VBT; TYPE T <: Public; Public = MUTEX OBJECT vbt: VBT.T; (* READONLY *) (* This field is filled in by the "Be" procedure. *) METHODS (* All clients should override "replace" *) replace (ch, new: VBT.T) RAISES {Multi.NotAChild}; (* Multi-split clients should override "insert" and "move" *) insert (pred, new: VBT.T) RAISES {Multi.NotAChild}; move (pred, ch: VBT.T) RAISES {Multi.NotAChild}; (* The following four methods have defaults. *) succ (ch: VBT.T) : VBT.T RAISES {Multi.NotAChild}; pred (ch: VBT.T) : VBT.T RAISES {Multi.NotAChild}; nth (n: CARDINAL): VBT.T; index (ch: VBT.T) : CARDINAL RAISES {Multi.NotAChild}; END; (* By definition, | mc.replace(ch, new) | `implements` | Multi.Replace(mc.vbt, ch, new) | mc.replace(ch, NIL) | `implements` | Multi.Delete(mc.vbt, ch) | mc.insert(pred, new) | `implements` | Multi.Insert(mc.vbt, pred, new) | `and` | mc.move(pred, ch) | `implements` | Multi.Move(mc.vbt, pred, ch) For the "replace" method, "ch" may be "NIL" if "mc.vbt" is a filter. There are no defaults for "replace", "insert", or "move". Some multiclasses may be able to implement "mc.move(pred,ch)" simply as | mc.replace(ch, NIL); mc.insert(pred, ch) The default "succ" method finds the successor of "ch" by a depth-first walk of "mc.vbt"'s descendants, starting after "ch", and stopping at the first "VBT" "w" for which | IsChild(mc.vbt, w) is "TRUE", or when all "mc.vbt"'s descendants have been visited. "succ" returns "NIL" if "ch" has no successor. The default "pred" method finds the predecessor of "ch" by repeatedly calling "mc.succ". The default "nth" method returns the nth child of "mc.vbt" by repeatedly calling "mc.succ". The default "index" method returns the index of "ch" in "mc.vbt" by repeatedly calling "mc.succ". *) PROCEDURE Be (v: VBT.T; mc: T); (* Make "v" into a multi by storing "mc" on "v"'s property set and setting "mc.vbt" to "v". *) PROCEDURE Resolve (v: VBT.T): T; (* Return the multiclass of "v", that is, the "mc" for which "Be(v,mc)" was previously called. Return "NIL" if there is no such "mc". *) PROCEDURE BeChild (v: VBT.T; ch: VBT.T); (* Make "ch" into one of "v"'s children that is exposed to the client via the "Multi" interface. It is possible for "ch" to be a child of more than one multi, and it is possible that "ch" is not related to "v" in the "VBT" hierarchy. *) PROCEDURE UnChild (v: VBT.T; ch: VBT.T); (* Unmark "ch" as one of "v"'s children that is exposed to the client via the "Multi" interface. *) PROCEDURE IsChild (v: VBT.T; ch: VBT.T): BOOLEAN; (* Return "TRUE" iff "BeChild(v,ch)" was previously invoked and "UnChild(v,ch)" has not been subsequently called. *) PROCEDURE Parents (ch: VBT.T): List.T (* of VBT.T *); (* Return a list of "VBT"s for which "IsChild(v,ch)" is "TRUE". The list may be "NIL". *) END MultiClass.