comp.lang.ada
 help / color / mirror / Atom feed
From: olivea!news.bu.edu!inmet!spock!stt@uunet.uu.net  (Tucker Taft)
Subject: Re: Ada 9X: Eliminating the re-emergence of predefined operations
Date: 16 Sep 93 21:49:03 GMT	[thread overview]
Message-ID: <CDGv9s.DDK@inmet.camb.inmet.com> (raw)

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

             reply	other threads:[~1993-09-16 21:49 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
1993-09-16 21:49 Tucker Taft [this message]
  -- strict thread matches above, loose matches on Subject: below --
1993-09-17 10:12 Ada 9X: Eliminating the re-emergence of predefined operations cis.ohio-state.edu!math.ohio-state.edu!darwin.sura.net!news.dfn.de!scsing.switch.ch!epflnews!disuns2.epfl.ch!lglsun!madmats
1993-09-14 19:53 cis.ohio-state.edu!math.ohio-state.edu!darwin.sura.net!spool.mu.edu!agate
1993-09-14  3:15 cis.ohio-state.edu!math.ohio-state.edu!howland.reston.ans.net!agate!dog.e
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox