[comp.lang.ada] Ada Language Change: Assignment Overloading

karl@grebyn.com (Karl Nyberg) (11/23/88)

[Ed. - this seems to have fallen through the cracks somewhere...]

-- Karl --

From: mendal@sierra.stanford.edu (Geoff Mendal)

I am surprised that no one has yet challenged the proposal to make
assignment an overloadable operation in the next revision of Ada.
There are many problems I have with this idea, which I feel compelled
to enumerate.  Most of these problems have been articulated by myself
and others before, but here goes.

1. Why simply restrict it to assignment?  Why not include membership,
   short-circuit control forms, indexing, selection, attributes, etc.?
   These are all basic operations.  I can think of many applications
   for overloading membership instead of having to write a function.
   Likewise, I can think of applications where an overloading of indexing
   would make my code more readable.  How I would love to be able to
   define my own attributes and use the attribute notation.  The point
   is that there is nothing special about assignment.  Therefore, it
   seems to me short-sighted to exclude other basic operations from the
   overloading status discussion.

   (Doug Bryan calls this the "infinity argument" so labeled because
   your ten changes, my ten changes, and so on add up to an infinite
   amount of changes that most likely make the situation worse, not
   better.)

2. Why is an overloading of assignment needed?  To avoid having to
   type an Assign procedure call?  This is silly.  While some readability
   may be gained by having assignment overloadable, program understandability
   dimishes.  This is one reason why there are so many restrictions on
   user-defined equality.  Increasing readability at the expense of
   understandability is not a good tradeoff.  Whining that typing a
   six character "Assign" procedure call makes a program too unreadable
   is poppy-cock.  Would you want to trust an overloading of ANYTHING
   to those programmers who are too lazy to type six character identifiers?
   Besides, coding is 10% of the software lifecycle.  Typing may account
   for 1% of that 10%.  Any language change whose sole benefit is to
   increase the productivity of 0.1% of the software lifecycle (at the
   possible expense of the remaining 99.9%) is highly suspect.

   It seems to me that when programmers say they want assignment overloaded,
   it is so that they can do much more than a simple assignment in the
   overloaded subprogram.  This would greatly reduce program understandability.
   In such cases, an Assign procedure is the right language construct to
   use.

3. Overloading assignment will break virtually all Ada programs.  We all
   know that operators which are not directly visible can be made so by a
   use clause (with some potential problems which I won't delve into) or
   a renaming declaration.  Consider the following compilation:

     with Text_Io;
     package P is
       X : Text_Io.File_Mode := Text_Io.In_File;
     end P;

   If assignment were to be overloadable, then it would not be allowed
   to be a basic operation.  Therefore, assignment would not be made
   directly visible in the above package.  One would need a use clause or
   a renaming declaration to achieve such direct visibility.  Thus,
   making assignment an overloadable operation is NOT an upward compatible
   change.  It would break virtually every program written, it would
   require changes to the scope and visibility rules, and would require
   little tweaks to the language such as in the semantics of renaming.

   These are the types of problems we don't need for the next revision of
   Ada.  I would like the proponents of assignment overloading to consider
   these issues before they jump on the bandwagon proclaiming a wonderful
   change to the language.

4. Finally, what would an overloading of assignment look like?  Would
   one parameter have to be mode in and the other mode out?  What about
   mode in out?  What about side effects?  Would it be a function or
   a procedure, or both?  What about overload resolution changes
   (consider the following program, is the "assignment" ambiguous)?

     procedure Main is
       type Int is new Integer;
       type A1 is access Integer;
       type A2 is access Int;

       function F return A1 is begin ... end;
       function F return A2 is begin ... end;
       procedure ":=" (L : out Integer; R : in Integer) is
       begin
         ...
       end;
       procedure ":=" (L : out Int; R : in Integer) is
       begin
         ...
       end;
     begin
       F.all := Integer'First;  -- ambiguous?
     end Main;

   Note that the above program would be legal if the two ":=" procedure
   bodies were removed.

   Next, consider the following example:

     procedure Erroneous is
       X : Integer;
       procedure ":=" (L : out Integer; R : in Integer) is
       begin
         null;
       end;
     begin
       X := Integer'First;
       -- Does reference to X's value here make the execution of the
       -- program erroneous?
     end;

   In the above example, we run into a serious problem.  Program provers
   might rely on the fact that if no exception is raised during the
   "assignment", that the the value is assigned to the object.  This follows
   Ada's current semantics.  But now through overloading assignment, we
   can make that very important assumption no longer true.  Program
   provers could no longer rely on the semantics of simple assignment
   thus significantly hindering the efforts to prove anything about
   a program.  Currently, if an assignment operation proceeds without
   exception, then it must be the case that the variable name is assigned
   the value specified (with some exceptions regarding assigning an
   uninitialized object to another).

   And yes, what would be the semantics of overloaded assignment for
   task objects and predefined File_Type objects?  Could it not be
   the case here that current semantics would be broken through clever
   use of overloading to assign limited objects?

The proponents of overloading assignment have also overlooked other
less costly solutions such as pre-processors that would transform
"overloaded assignment" into Ada procedure calls, implementation-defined
pragmas, etc.  The technology for these kinds of solutions are readily
available.  If you need such capability, pound on your local Ada
APSE vendor for the tools.  This is an APSE issue, not a language
issue, you know.

In summary, there are many areas of the language that need attention.
Overloading assignment may sound like a great idea on the surface but
the problems exposed by any tampering with the current semantics outweigh
any readability benefit that might be gained.

You may now shoot me with arrows.  I don't care... I'm on holiday.

gom

leake@cme-durer.ARPA (Stephe Leake) (11/23/88)

Thanks to Geoff Mendal for giving a careful, reasoned response to the
suggestion of allowing overloading of ":=". I would like to respond to
a couple of his points:

	1. Why simply restrict it to assignment? ...

Good point; we need to consider each in turn, something I assume the
original language design team did. Where can I get the documentation
on their decisions?

	2. Why is an overloading of assignment needed? ...

I stand guilty of sloppy thinking: I have accused others of not giving
specific examples of what changes would gain, and now I have none.

	3. Overloading assignment will break virtually all Ada programs. ...

A very good point!

	4. Finally, what would an overloading of assignment look like? ...
	   (consider the following program, is the "assignment" ambiguous)?

     procedure Main is
       type Int is new Integer;
       type A1 is access Integer;
       type A2 is access Int;

       function F return A1 is begin ... end;
       function F return A2 is begin ... end;
       procedure ":=" (L : out Integer; R : in Integer) is
       begin
         ...
       end;
       procedure ":=" (L : out Int; R : in Integer) is
       begin
         ...
       end;
     begin
       F.all := Integer'First;  -- ambiguous?
     end Main;

   Note that the above program would be legal if the two ":=" procedure
   bodies were removed.

The assignment is ambiguous because the second function F is not a
"pure" assignment; it is also a type conversion. All overloading is
subject to this type of abuse; the fact that it is also possible in
overloading assignment is not significant. In fact, carefull use of
this possibility could lead to more readable programs, by eliminating
lots of explicit type conversions (although my first reaction is that
the program should be restructured: explicit type conversions are
usually an indication that something is fundamentally wrong).

     procedure Erroneous is
       X : Integer;
       procedure ":=" (L : out Integer; R : in Integer) is
       begin
         null;
       end;
     begin
       X := Integer'First;
       -- Does reference to X's value here make the execution of the
       -- program erroneous?
     end;

Yes, it is erroneous. But again, the problem is the idiotic definition
of ":="; the same idiotic definition could be given for "*", with
equally erroneous results. This is not unique to ":=". (Note that the
DEC compiler will issue a warning on compiling ":=", since the out
parameter is never given a value).

   ... Currently, if an assignment operation proceeds without
   exception, then it must be the case that the variable name is assigned
   the value specified (with some exceptions regarding assigning an
   uninitialized object to another).

If we consider expressions results passed as actual parameters, the
same problem arrises with idiotic definitions of "*". I agree that
":=" seems more of a problem, but it is still not unique.

   And yes, what would be the semantics of overloaded assignment for
   task objects and predefined File_Type objects?  Could it not be
   the case here that current semantics would be broken through clever
   use of overloading to assign limited objects?

These cannot be overloaded, since they are declared limited private in
packages that we cannot modify; just like other operators, assignment
for a limited private type should only be declarable in the same
declaration region the type is declared in.

	The proponents of overloading assignment have also overlooked other
	less costly solutions such as pre-processors that would transform
	"overloaded assignment" into Ada procedure calls, implementation-defined
	pragmas, etc.

These are definitely inferior solutions; if you want pre-processors,
use C! :-)

On the whole, I think the arguments in 2 and 3 are sufficient. I
hereby withdraw my request for overloading ":=". And thanks again for
the time spent.

Stephe Leake 	(301) 975-3431 		leake@cme.nbs.gov
National Institute of Standards and Technology
(formerly National Bureau of Standards)
Rm. B-124, Bldg. 220
Gaithersburg, MD  20899

trent@unix.SRI.COM (Ray Trent) (11/24/88)

In article <8811221935.AA21274@grebyn.com> karl@grebyn.com (Karl Nyberg) writes
>2. Why is an overloading of assignment needed?  To avoid having to
>[much flamage about overloading equals]

This standard argument against allowing the overloading of the ":="
operator ignores the fact the programmers may want *semantics*
in their type declarations instead of just syntax. Types are not 
static objects that can be completely defined at compile time,
however much the designers of Ada want to think they are.

I offer:
  type Fraction is record
    Numerator, Denominator : Integer
  end record;

The Ada apolgists would have us write the semantics for ensuring
LCD form for the type Fraction into *each and every operator*
that acts upon 2 items of this type, instead of having that 
functionality in the assignment operator, where it belongs. The point 
is, readable or not, ":=" should validly ensure the *semantics* of
every type it is defined for, as well as the pure syntactical elemants.

I claim that:
  A, B, C : Fraction;
  A := B / C;
is both more understandable and readable than:
  A, B, C : Fraction;
  Fraction_Ops.Assign(A, Fraction_Ops.Divide(B, C))

I realize that the type Fraction is a poor example. I don't have time
to explain a good example. Everyone out there that claims to be a 
programmer should be able to find one and understand it with a 
little work.

The argument that pre-processors can be used to acheive this effect is
bull. It ignores the absolute fact that *no one* maintains, reads, or
is expected to understand the processed code. This is a null argument.
If you state that your reason for disallowing assignment overloading
is to improve understandability, it is inconsistent to allow pre-processing
that gets around the problem. The original code, which is all that
anyone reads, is exactly as understandable with assignment overloading
as it is with pre-processing in an Assign(L, R) (9 extra characters, BTW,
not 6).
-- 
"Our little lives get complicated
 It's a simple thing
 Simple as a flower
 And that's a complicated thing"                     ../ray\..

billwolf@hubcap.clemson.edu (William Thomas Wolfe,2847,) (11/24/88)

From article <8811221935.AA21274@grebyn.com>, by karl@grebyn.com (Karl Nyberg):
> From: mendal@sierra.stanford.edu (Geoff Mendal)
> 
> 1. Why simply restrict it to assignment?  Why not include membership,
>    short-circuit control forms, indexing, selection, attributes, etc.?
>    These are all basic operations.  I can think of many applications
>    for overloading membership instead of having to write a function.
>    Likewise, I can think of applications where an overloading of indexing
>    would make my code more readable.  How I would love to be able to
>    define my own attributes and use the attribute notation.  The point
>    is that there is nothing special about assignment.  Therefore, it
>    seems to me short-sighted to exclude other basic operations from the
>    overloading status discussion.

   First, assignment is a "fundamental" operation; except for attributes,
   the other things you've suggested apply only to specific classes of
   ADTs.  As for attributes, I think we could live without them if 
   appropriate procedures and functions were defined over the predefined
   ADTs; having attributes for predefined ADTs and functions for user-defined
   ADTs is another inconsistency.  Procedures and functions are definitely
   necessary; the attribute mechanism is not.

   Now another aspect of this problem is the principle that users should
   be able to define ADTs which are just as powerful as the predefined
   ADTs; obviously, this is not presently the case with Ada.  With regard
   to attributes, I think elimination of the feature will bring Ada into
   compliance with this principle, and result in general simplification.

   Another reason is that assignment procedures need to be invoked as part
   of the evaluation of a user-defined ADT which is passed by value.  No
   similarly vital function is performed by the other operations suggested.

   The argument that the operations listed (except assignment and attributes)
   should be user-programmable with respect to user-defined ADTs is reasonable,
   but clearly assignment is in a higher class of importance than the others.

> 4. Finally, what would an overloading of assignment look like?  Would
>    one parameter have to be mode in and the other mode out?  What about
>    mode in out?  What about side effects?  Would it be a function or
>    a procedure, or both?  

   procedure ":=" (FIRST_OBJECT  : in out TYPE;
                   SECOND_OBJECT : in     TYPE);

   would seem appropriate.

billwolf@hubcap.clemson.edu (William Thomas Wolfe,2847,) (11/24/88)

From article <8811221935.AA21274@grebyn.com>, by karl@grebyn.com (Karl Nyberg):
> From: mendal@sierra.stanford.edu (Geoff Mendal)
> 
>    Consider the following compilation:
> 
>      with Text_Io;
>      package P is
>        X : Text_Io.File_Mode := Text_Io.In_File;
>      end P;
> 
>    If assignment were to be overloadable, then it would not be allowed
>    to be a basic operation.  Therefore, assignment would not be made
>    directly visible in the above package.  One would need a use clause or
>    a renaming declaration to achieve such direct visibility.  Thus,
>    making assignment an overloadable operation is NOT an upward compatible
>    change.  It would break virtually every program written, it would
>    require changes to the scope and visibility rules, and would require
>    little tweaks to the language such as in the semantics of renaming.

   Why can't an overloadable operation remain as a basic operation?

   In order to preserve compatibility, the "old" interpretation of
   assignment could be kept as the outermost interpretation (deepest
   in the background), available as a default assignment procedure.

>    Program provers might rely on the fact that if no exception is raised 
>    during the "assignment", that the the value is assigned to the object.  
>    This follows Ada's current semantics.  But now through overloading 
>    assignment, we can make that very important assumption no longer true.  
>    Program provers could no longer rely on the semantics of simple 
>    assignment, thus significantly hindering the efforts to prove 
>    anything about a program.  

   And what about the overloadable relational operators???

   Program provers cannot now assume that "=" really means equality,
   nor can they assume that some side effect will not occur during the
   evaluation of an equality operator.  There is plenty of precedent here.
   If we go ahead and overload assignment, the program prover will be able
   to exercise one simple, consistent rule: "Assume nothing".  I think this
   is an excellent mode of thought to force a program prover into.  

>    And yes, what would be the semantics of overloaded assignment for
>    task objects and predefined File_Type objects?  Could it not be
>    the case here that current semantics would be broken through clever
>    use of overloading to assign limited objects?

   The same argument applies in general to the overloadable relational 
   operators; a possible solution would be to require that operators,
   if they are defined over a private or limited private type, must
   be defined within the package specification in which the private
   or limited private type is defined.  This covers File_Type objects;
   since task objects are woven directly into the language rather than
   being included in a predefined package, there isn't even a package
   specification into which an overloadable operator could be inserted. 

> The proponents of overloading assignment have also overlooked other
> less costly solutions such as pre-processors that would transform
> "overloaded assignment" into Ada procedure calls, implementation-defined
> pragmas, etc.  The technology for these kinds of solutions are readily
> available.  If you need such capability, pound on your local Ada
> APSE vendor for the tools.  This is an APSE issue, not a language
> issue, you know.

    Wrong.  The ability to cleanly define abstract data types 
    is very much a language issue.  Implementation-defined pragmas
    would annihilate portability.  Preprocessors would have one hell
    of a time implementing "If this procedure call involves passing
    a user-defined ADT by value, then generate a temporary variable
    of that type, invoke ASSIGN on that temporary (assuming we adhered
    to the convention of using the name ASSIGN rather than, for example,
    COPY or DUPLICATE), and pass the temporary instead, and remember 
    to invoke DESTROY on the temporary afterward"...

    There's no way around it.  Assignment needs to be overloadable.

billwolf@hubcap.clemson.edu (William Thomas Wolfe,2847,) (11/24/88)

From article <3657@hubcap.UUCP>, by billwolf@hubcap.clemson.edu (William Thomas Wolfe,2847,):
>> 4. Finally, what would an overloading of assignment look like?  Would
>>    one parameter have to be mode in and the other mode out?  What about
>>    mode in out?  What about side effects?  Would it be a function or
>>    a procedure, or both?  
$ 
$    procedure ":=" (FIRST_OBJECT  : in out TYPE;
$                    SECOND_OBJECT : in     TYPE);
$ 
$    would seem appropriate.

   In order to avoid infinite recursion with regard to the evaluation
   of the SECOND_OBJECT as a value parameter, there would need to be
   some rule whereby the "old" version of assignment would always be
   applied during the evaluation of an in parameter to an assignment
   procedure.