From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.5-pre1 (2020-06-20) on ip-172-31-74-118.ec2.internal X-Spam-Level: X-Spam-Status: No, score=-1.9 required=3.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.5-pre1 Date: 16 Sep 93 21:49:03 GMT From: olivea!news.bu.edu!inmet!spock!stt@uunet.uu.net (Tucker Taft) Subject: Re: Ada 9X: Eliminating the re-emergence of predefined operations Message-ID: List-Id: In article <1993Sep14.022914@lglsun.epfl.ch> madmats@lglsun.epfl.ch (Mats Weber) writes: > . . . >Now, and this is where the bad things happen, Ada 9X allows "=" to be >redefined for any type, so that predefined equality can be made to >re-emerge just as the predefined "*" does in the above example. I think >this is very dangerous because an invalid equality can break the >abstraction for which it applies. In Ada 9X, predefined operators do not "reemerge" for tagged types, or private types whose full type is tagged. We considered extending this rule to nontagged types, but there were some subtle technical and upward-compatibility reasons why that didn't work. (See below.) So, the bottom line is that if you want to fully control the operations on a type, and prevent "reemergence" of predefined operators in a generic instantiation, then you will have to use a tagged type. Here is the more technical explanation (this might be a question on next year's Ada 9X language lawyer bar exam ;-): For nontagged types, the rules for overriding operators and other inherited (aka "derivable") subprograms are pretty lax. In particular, the subtypes don't have to match, and in the case of a procedure, even the parameter modes don't have to match (not a problem for operators since they are functions). Here is a particularly pathological example: type T is new Integer; subtype Positive_T is T range 1..T'Last; function "+"(A, B : Positive_T) return Positive_T; -- This overrides the predefined "+" of T. -- Note that the parameter subtypes don't match those -- of the predefined "+". generic type Q is range <>; function Double(X : Q) return Q; function Double(X : Q) return Q is begin return X + X; -- ** -- end Double; function T_Double is new Double(T); Z : T := T_Double(-5); The "+" appearing on the line marked "-- ** --" is the predefined "+" in both Ada 83 and Ada 9x. If the predefined "+" did not reemerge, then not only would the code generated for T_Double have to call a user-provided "+", it would also have to do a constraint check against the range of Positive_T before calling the user's "+". This could make sharing generics significantly harder and less efficient, requiring not only out-of-line calls on every use of an operator, but also the generation of "thunks" to handle parameter subtype mismatches like this one. Ada 9X exacerbates this situation a bit, because it supports formal derived types, so that the formal type can have more than just the predefined operators, it can also have a bunch of primitive procedures. The actual type passed against the formal derived type might have overridden some of these primitive procedures with procedures having different parameter modes, which wouldn't just affect the code quality of shared generics, but would affect the legality of an instantiation, thereby breaking the generic contract model. As it turns out, none of these problems arise with tagged types. This is because the parameter subtypes and modes must match when overriding a predefined operator or an inherited subprogram. To go along with this, tagged types already have a very handy type descriptor (at least in most implementations) which is exactly what a shared generic needs to call things like "=" indirectly. Again, the bottom line is that, if you want to fully control an abstract data type, which includes defining your own initialization, finalization, assignment, and equality, you will have to use tagged types. Note that you can declare a type as (untagged) private and still have the full type tagged, so you don't need to change the external interface to the type. One last technical point: The reemergence problem doesn't only come up with generics. It also comes up with type composition. That is, if a component has its own equality operator, how does that affect the (predefined) equality operator for the composite type. Ada 83 skirts this isssue because the only kinds of types for which you can easily define your own "=" are limited, and limited types "poison" any composite type that contains them (even when they have a user-defined "=") by making the composite type limited as well. So there is no composition of "=" to worry about. In Ada 9X (as of version RM9X;3.0), the "=" operator for a composite type is similar to a generic in that the predefined "=" reemerges for untagged components, but the user-defined "=" is what counts for tagged components. So once you define your own "=" for a tagged type, the predefined "=" is gone for good -- it is not visible in a generic, nor will it reemerge if you wrap the type in a record (even an untagged record) or an array. Conclusion: user-defined "=" for untagged, nonlimited types is not as useful as it could be. It is best used for situations where the predefined "=" is well-defined, but perhaps not as "generous" as it could be about when two things are equal. By analogy to Lisp, for untagged types the predefined "=" would correspond to the Lisp "EQ" whereas the user-defined "=" would correspond to the Lisp "EQUAL." Note that to change the way assignment works for a type, it will have to be tagged anyway, so this issue may not come up that much, because the truly abstract data types will be tagged for other reasons already. By the way, one possible alternative approach to the problem, which would not impose much of a burden on shared generics, would be to prevent reemergence for the "=" of all record types, whether tagged or untagged. One might then argue for disallowing overriding the predefined "=" for other types (though you could still overload it). These choices are always hard... >Mats Weber >Software Engineering Lab >Swiss Federal Institute of Technology >CH-1015 Lausanne >Switzerland >e-mail: weber@lglsun.epfl.ch S. Tucker Taft stt@inmet.com Ada 9X Mapping/Revision Team Intermetrics, Inc. Cambridge, MA 02138