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.