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: fac41,c52c30d32b866eae X-Google-Attributes: gidfac41,public X-Google-Thread: 103376,2ea02452876a15e1 X-Google-Attributes: gid103376,public X-Google-Thread: 1108a1,c52c30d32b866eae X-Google-Attributes: gid1108a1,public From: ncohen@watson.ibm.com (Norman H. Cohen) Subject: Re: Real OO Date: 1996/05/06 Message-ID: <4mls4h$sau@watnews1.watson.ibm.com> X-Deja-AN: 153368606 distribution: world references: <4j9p3a$uo5@watnews1.watson.ibm.com> <4kbqun$iiv@watnews1.watson.ibm.com> <6850x6pV3RB@herold.franken.de> organization: IBM T.J. Watson Research Center reply-to: ncohen@watson.ibm.com newsgroups: comp.lang.eiffel,comp.lang.ada,comp.object Date: 1996-05-06T00:00:00+00:00 List-Id: In article <6850x6pV3RB@herold.franken.de>, jhd@herold.franken.de (Joachim Durchholz) writes: |> As I understand it, you mean the multiple dispatching mechanisms |> (a.k.a. classwide operations). No, that's not what classwide operatins are. Your post reflects a number of misconceptions. |> While I agree that these can be useful, I noted a few problems |> that can arise in this context: |> |> 1) Ambiguity of routine to be called. |> Consider the following situation: I have two classes A and B that |> each have a descendant A' and B', respectively. |> Now let's define a class-wide function (just class names in the |> parameter list) |> f(A, B) |> meaning whenever f is called, parameters my be of class A and its |> descendants resp. B and its descendants. What you're describing here is impossible in Ada. It's hard to figure out what you really mean because you are using the word "class" in its Eiffel sense rather than it's Ada sense to describe an Ada example. In Ada, a class is not a type, but a SET OF TYPES. In particular, the set of tagged types directly or indirectly derived from a common root forms a "derivation class". ("Deriving" from a type means defining a descendant type.) For each type T at the root of a tree or subtree in the derivation hierarchy, there is a "classwide type", T'Class, whose values are taken from the discriminated union of the types in the class. One cannot derive from a classwide type. (By "discriminated union," we mean that for each value V of each type in the class, there is a corresponding value in T'Class, and that the corresponding value in T'Class includes a "tag" identifying the type of the original value V.) An Ada function parameter is declared to belong to a particular type, not a particular class, so if there is a function declared to take an A parameter and a B parameter, A and B must be types, not classes. Let us suppose that A and B are ordinary tagged types, NOT classwide types (so that A'Class and B'Class are the corresponding classwide types). If you write a procedure procedure P(X: in A); in the same package in which A is declared, then there is a version of P (either inherited or explicitly overridden) in each type descended from A. P can be called with an actual parameter of type A'Class, in which case the call dispatches to the appropriate version of P based on the tag of the actual parameter. If you write a procedure procedure Q(X: in A'Class); it is not an operation of type A, so it is not inherited in the usual sense by types derived from A. However, in a call, the actual parameter may belong to A'Class, A, or any type descended from A. Unlike P, Q never dispatches. No matter what the tag of the actual parameter is, Q always executes the same procedure body. The body of Q must be written in such a way that it depends only on properties common to all types in the class. (Ada rules allow this to be enforced at compile time.) Now suppose A and B are declared in the same package. It is illegal to declare procedure R(X: in A; Y: in B); --which would appear to be a procedure that dispatches based on both the tag of X (identifying a type in the class rooted at A) and the tag of Y (identifying a type in the class rooted at B). THERE IS NO CLOS-LIKE MULTIPLE DISPATCH IN ADA. You CAN declare procedure S(X: in A'Class; Y: in B'Class); and this poses no problems. It does not dispatch. It can take a first parameter belonging to A'Class, A, or any descendant of A along with a second parameter belonging to B'Class, B, or any descendent of B. It always invokes the same procedure body, which must be written to exploit only those properties common to all types in the class rooted at A (for the first parameter) and those properties common to all types in the class rooted at B (for the second parameter). It is also possible to write procedure T(X:in A; Y: in B'Class); which dispatches based on the tag of X to the appropriate version of T (inherited by descendants of A but not by descendants of B). For their manipulations of the second parameter, all the versions of T exploit only those properties common to all types in the class rooted at B. The procedure procedure S(X: in A'Class; Y: in B); is analogous. |> When I write an additional function |> f(A', B) -- redefinition 1 |> any calls to f that have their first parameter of class A' (or |> further down the inheritance chain) will get to call this version |> of f. |> Likewise, a function |> f(A, B') -- redefition 2 |> will do the same for B'. |> But which of these gets called if the parameters are of type A' |> *and* B'? Both functions are applicable, redefinition 1 and |> redefinition 2. As noted above, this situation does not arise in Ada. A function cannot be a dispatching function of two different types. |> 2) Combinatorial explosion. |> |> The number of possible class-wide functions is (number of |> descendants of A) times (number of descendants of B) |> ("descendant" including the class itself here). |> |> This explosion may not be visible in the source code; however, |> this appearance is deceiving. After all, even if there is no code |> necessary for most of the combinations, you have to check *all* |> of the combinations and look wether an overriding class-wide |> function is necessary. Several misconceptions here. First, classwide subprograms have parameters belonging to classwide types, which cannot be derived from, so classwide subprograms are never overridden. Second, unlike dispatching subprograms, which are written to handle the distinctions among different types in a class, classwide subprograms are written to handle things that are common to all types in the class. For each class (i.e., set of types) precisely one version of a classwide subprogram is necessary. That's where the name "classwide" comes from--one version applies to all types in the class. |> However, the combinatorial explosion effect makes me more than |> reluctant to accept multiple dispatching as a desirable feature, |> even if it is useful in special cases. Quite possibly, but you should address that objection to advocates of CLOS. Ada does not have the sort of multiple dispatching mechanism you envision. -- Norman H. Cohen ncohen@watson.ibm.com