From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-0.3 required=5.0 tests=BAYES_00, REPLYTO_WITHOUT_TO_CC autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 1108a1,c52c30d32b866eae X-Google-Attributes: gid1108a1,public X-Google-Thread: 103376,2ea02452876a15e1 X-Google-Attributes: gid103376,public X-Google-Thread: fac41,c52c30d32b866eae X-Google-Attributes: gidfac41,public From: ncohen@watson.ibm.com (Norman H. Cohen) Subject: Re: Real OO Date: 1996/03/22 Message-ID: <4iuvmi$113p@watnews1.watson.ibm.com> X-Deja-AN: 143743861 distribution: world references: <4id031$cf9@dayuc.dayton.saic.com> organization: IBM T.J. Watson Research Center reply-to: ncohen@watson.ibm.com newsgroups: comp.lang.ada,comp.lang.eiffel,comp.object Date: 1996-03-22T00:00:00+00:00 List-Id: In article , donh@syd.csa.com.au (Don Harrison) writes: |> In Eiffel, there is only one species of |> type - the class - which may be viewed as specific or class-wide depending on |> the context. This makes modelling considerably easier. |> |> Ada complicates matters by forcing an atificial distinction of specific versus |> classwide depending on usage. Since the formal and actual parameters of an |> operation may be either specific or classwide, the number of possible |> combinations is 4 compared with 1 in Eiffel. To my mind, this is 4 times more |> complicated than is really needed. This is not an artificial distinction. Let us consider actual parameters and formal parameters separately. In the case of actual parameters, it is a formalization of the distinction that Bertrand Meyer recognizes between the static type and the dynamic type of a reference. Think of an Ada actual parameter of a specific type as an Eiffel reference whose dynamic type is known to be identical to its static type. A method call can be far more efficient if this knowledge is conveyed to the compiler, and it is common in practice for this knowledge to be available. (The extra efficiency arises not only from saving a cycle or two for an indirect jump, but also because of the possibility of inlining the method body or performing precise interprocedural analysis.) In the case of formal parameters, the use of a classwide type or specific type reflects the distinction between a single type and the hierarchy of types descended (in zero or more steps) from that type. (In Eiffel, the word "class" refers to any one of these types; in Ada, the word "class" refers to the hierarchy, so "classwide" means "hierarchy-wide".) A classwide subprogram (i.e., one with classwide formal parameters) is one whose algorithm is the same for all objects in the hierarchy. A dispatching subprogram (i.e., one with specific formal parameters) is one whose algorithm depends on the tag (in Eiffel terms, the dynamic type) of the actual parameter. The body of a classwide subprogram relies only on properties common to all types in the hierarchy, i.e., features introduced at the root of the hierarchy. These may include record components, other classwide subprograms, and dispatching operations. For a one-parameter subprogram, the effect of a classwide subprogram could be achieved by a dispatching subprogram that is never overridden. Making it classwide simply documents the fact that the algorithm does not depend on the tag of the parameter, and causes the compiler to catch any attempt to override. The real power of a classwide program arises with multiple parameters. In Eiffel, dispatching is controlled by the one object whose method is invoked (the x in x.f()). In an Ada dispatching subprogram, there can be multiple parameters controlling the dispatching. Consider a hierarchy for geometric figures, with Shape_Type at the root and types such as Circle_Type, Triangle_Type, and Rectangle_Type at the leaves. There may be a dispatching operation Corresponding_Parts_Equal defined (as an abstract function) for Shape_Type and overridden for each shape. For example: function Corresponding_Parts_Equal (C1, C2: Circle_Type) return Boolean is begin return C1.Radius = C2.Radius; end Corresponding_Parts_Equal; function Corresponding_Parts_Equal (R1, R2: Rectangle_Type) return Boolean is begin return (R1.Base = R2.Base and R1.Height = R2.Height) or (R1.Base = R2.Height and R1.Height = R2.Base); end Corresponding_Parts_Equal; Each time a new kind of shape is introduced to the hierarchy, a new overriding version of Corresponding_Parts_Equal, concerned only with the features of that kind of shape, is written. The call Corresponding_Parts_Equal(Shape1, Shape2), where Shape1 and Shape2 are of type Shape_Type'Class (in Eiffel terms, their static types are Shape_Type and their dynamic types are unknown), will dispatch to the first body above if the dynamic types of Shape1 and Shape2 are both Circle_Type, to the second body above if the dynamic types are both Rectangle_Type, and so forth. But if Shape1 and Shape2 have different dynamic tags, there is no sensible way to check that their corresponding parts are equal, and a run-time error results. That leaves the problem of how to determine whether two arbitrary Shape_Type'Class values, possibly with different tags, are congruent, and this is where classwide subprograms come in. There is no requirement that the parameters of a classwide subprogram have the same tag. Therefore, we can write: function Congruent (Shape1, Shape2: Shape_Type'Class) return Boolean is begin return Shape1'Tag = Shape2'Tag and then Corresponding_Parts_Equal (Shape1, Shape2); end Congruent; When the shapes have different tags, the function immediately returns False without invoking Corresponding_Parts_Equal. -- Norman H. Cohen ncohen@watson.ibm.com