mendal@ANNA.STANFORD.EDU (Geoff Mendal) (11/29/88)
I will respond briefly to some of the replies made to my original assignment overloading message. Lines with ">>" are from my original message, lines with ">" are responses to my original message. I am a bit shocked that some people apparantly agree with me... I'm not used to that sort of thing. >Date: 23 Nov 88 22:57:59 GMT >From: hubcap!billwolf@gatech.edu (William Thomas Wolfe,2847,) >Subject: Ada Language Change: Assignment Overloading > >> 1. Why simply restrict it to assignment? Why not include membership, >> short-circuit control forms, indexing, selection, attributes, etc.? >> These are all basic operations.... > > 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. Wrong. Membership, qualification, attributes, and explicit type conversion are all "fundamental" operations defined for EVERY type. To argue that assignment is special requires more justification than "we can live without X and Y is necessary". Who can live without X? I can most certainly live without assignment overloading. Does this mean that overloading assignment is a good/bad idea? Nonsense. Rethink your argument. > 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. I don't understand this at all. You are assuming pass by value for an ADT? Rediculous. The LRM only states that scalars and access values are passed by copy. In general, for an ADT, you cannot assume pass by value and if your program depends on it, your program will execute erroneously. Justifying a language change based on a set of programs which are known to execute erroneously it itself an erroneous argument. If an "assignment procedure needs to be invoked as part of the evaluation of a user-defined ADT" then one can explicitly write the Ada code necessary for this. Default components for records provide a simple solution here. There are other solutions as well. None of the solutions REQUIRE assignment to be overloaded. > 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. I strongly disagree. Assignment is assignment. A relational operator is a relational operator. Are we going to change the language by taking a popular vote of which operations are "higher class" than others? Such justification for a language change is rediculous. So far, I have seen no justification why assignment should be overloaded and not other basic operations. Consider usability, readability, understandibility, etc. These should drive the justification, not someone's arbitrary "higher class" argument. My argument is that while readability might be increased, understandability will be diminished and therefore we should reject the notion that overloading assignment is a good idea. The designers of Ada went out of their way to make typing Ada programs more difficult/time-consuming so that understanding them would be easier. Any language change should not compromise understandability for the sole gain of making programs easier to type. >Date: 23 Nov 88 19:13:34 GMT >From: trent@unix.sri.com (Ray Trent) >Subject: Ada Language Change: Assignment Overloading [some verbage deleted] > >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. [fraction example deleted] > >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. [more fraction examples deleted] First, assignment is NOT an operator. It is a basic operation. Operators are completely different in that they follow different scope/visbility rules and are afforded some luxeries (overloading) not currently available to basic operations. I tried to make this point clear in my original message but it is obvious that still not everyone understands the difference. Read the LRM and be enlighted. Now, of course programmers want semantics in their type declarations and I believe that Ada provides some of these semantics through predefined behavior of basic operations and operators. But I disagree that having the complete semantics for a type defined in an "assignment operator" is appropriate or even desired. Assignment already has a very well defined semantics. Read the LRM. So what is the problem? You don't like those semantics and you would prefer to alter them? Fine, but I fail to see why ":=" has to be the syntagma which carries your favorite semantics (which may not be my favorite semantics). One of the examples that I deleted above was "A := B / C;" where A, B, and C were of some ADT (Fraction). If I understand the argument for placing the semantics in assignment instead of having the programmer define the semantics in each user-defined operation, then how would the semantics of passing the expression "B / C" to some subprogram formal be handled? There is no "assignment" here. The semantics have to be part of the division operation. Perhaps you are arguing that indeed "assignment semantics" should be a part of EVERY operation. This is a completely different language change, far more involved than a "simple" overloading of "assignment". Perhaps those who are involved with Ada formal definition projects (DDC, etc.) can shed some light on what is involved here and if such would be useful. >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. Quite the contrary. The whole idea of a pre-processor or translation tool is to remove the need to "read" the processed version. How many Ada programmers spend their time disassembling and reading the output of their compilations? A compiler is a translation tool. The idea being that Ada is more readable/understandable/etc. than assembly. So why is it that defining a mapping from some pre-processor to Ada is met with such cynicism? It simply provides an additional layer of abstraction, which, the last time I looked, was thought to be a good idea. Those who are convinced that there is nothing above/beyond Ada should continue to keep their blinders on so that they won't have to worry about keeping up with computer science and software engineering. If others in our field had adopted this attitude, we'd still be programming by wire wrapping and debugging with oscilloscopes. (It is a sad commentary that there are still Ada programmers out there who still do not understand the need for and utility of an APSE. You can spot them right away... they're the ones who think that the only way to improve/change things is by modifying the language.) >Date: 24 Nov 88 01:55:31 GMT >From: hp-sdd!ncr-sd!ncrcae!hubcap!billwolf@hplabs.hp.com (William Thomas Wolfe,2847,) >Subject: Ada Language Change: Assignment Overloading > > 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. Yech! The current language definition is clear and consistent. A basic operation (such as assignment) cannot be overloaded. Overloading is defined only for subprograms, single entries, operators, and enumeration literals. My point was that if assignment was to be overloaded, then it would most likely have to be reclassified as an operator or a procedure. Otherwise, this language change would require much more work. Having assignment as the only basic operation which could be overloaded makes the semantics of "assignment" more murky. Overloading is complex enough without adding a new special case to it. And for what benefit? I still haven't seen a response that illustrates a useful case where overloading assignment would do anything useful. Does anyone have such a case? Or is this basically a theoretical argument whereby the impact of a language change will not be understood until it has been made and programmers start to experiment with it? >> 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. > > 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. Well, not really. Since "=" can only be overloaded by the user for limited types, it is not a good example. "*" is a better example. But the point is that the current semantics of assignment do allow program provers to make certain assumptions which make the job of writing a program prover easier. While it is certainly possible to write a program prover which does not make use of the current assignment semantics, it is far harder to do so. The point being that there exist applications of Ada out there which will suffer somewhat from this proposed language change. Whether this is a desired result is debatable (do we really want to force the program proving folks to go back and undertake a major redesign because a few programmers hate to type ASSIGN?). >> 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. > > 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. I don't understand this argument at all. Clearly one can write ASSIGN procedures by hand to solve this sort of thing. The only difference is that ASSIGN (X, Y) has to be written instead of "infix" X := Y. So why does assignment need to be overloaded? And if one can write the code with the intended semantics by hand, then why cannot an advanced APSE tool do so? Is your argument that the state of APSE technology is not sufficient to solve the problem, and therefore we have to solve it as a language problem? This is again a silly argument for making a language change and would prove my case that this is indeed an APSE issue, not a language issue. *********** Since overloading of assignment is not a very important issue, I'll refrain from making any further comments about it. I'll get back to doing more important things... writing pre-processor tools for Ada. gom
dd@sei.cmu.edu (Dennis Doubleday) (11/29/88)
In article <8811282217.AA04896@ajpo.sei.cmu.edu> mendal@ANNA.STANFORD.EDU (Geoff Mendal) writes: >But the point is that the current semantics of assignment do allow >program provers to make certain assumptions which make the job of >writing a program prover easier. While it is certainly possible to >write a program prover which does not make use of the current >assignment semantics, it is far harder to do so. The point being that >there exist applications of Ada out there which will suffer somewhat >from this proposed language change. Whether this is a desired result >is debatable (do we really want to force the program proving folks to >go back and undertake a major redesign because a few programmers hate >to type ASSIGN?). I agree that overloading of ":=" is a bad idea, but your line of reasoning here is not convincing (to me). I would change your last question to "are we really going to limit programmers to only those language constructs which the program proving folks find easy to handle?". If the answer is "yes", then we're not going to get much real work done for the next decade, at least. Dennis Doubleday dd@sei.cmu.edu Software Engineering Institute (412)268-5873 Carnegie Mellon University Pittsburgh, PA 15213
trent@unix.SRI.COM (Ray Trent) (11/30/88)
In an article mendal@ANNA.STANFORD.EDU (Geoff Mendal) writes: >>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 > >First, assignment is NOT an operator. It is a basic operation. The argument is that it should be. (and is, in any sensible (i.e. non-Ada) definition of the word operator) That there is no reason to have "basic" operators that are "special". >One of the examples that I deleted above was "A := B / C;" >where A, B, and C were of some ADT (Fraction). If I understand the >argument for placing the semantics in assignment instead of having the >programmer define the semantics in each user-defined operation, then >how would the semantics of passing the expression "B / C" to some >subprogram formal be handled? There is no "assignment" here. The Fine, perhaps a better example is assigning to an object that should be garbage-collected before assignment. (always, or the program will be erroneous (not in the Ada sense)) Which makes more sense, putting garbage collection in assignment, or assuming the programmer will always call a garbage collector while assigning? Even if the programmer is a code maintainer, and not the designer? If you are wondering why I chose my original example, consider A := (B / C * D) + ... + (Q / (3/4)). (all variables are of type fraction, and an appropriate "/"(A,B : INTEGER) is defined) Do you still want LCD maintainance in the arithmetic operations? Of course, you could always force A := LCD(foo). What if someone wants to modify the program? Aren't they going to wonder/forget about this? If you are worried about passing the expression B / C as a parameter, my answer is: if you have a procedure where LCDness is necessary for proving something, you can *always* simply make "in" parameters "in out" parameters. This *ensures* that an input variable will be in LCD form. (if assignment is overloadable and is overloaded as suggested) "Requiring" a A := LCD(B/C) does not ensure the validity of something passed to a sub-program. If assignment were overloadable, the writer of an Ada spec for operations involving fractions could be *sure* of always having something in LCD form when passed to a subprogram by overloading ":=" and passing all variables as "in out" parameters. The only other way to do this is force *all* subprograms to perform LCDing on their outputs (or inputs) whether that condition is necessary or not. This would make the operation A := <very complicated expression with *many* arithmetic operations> extremely slow (potentially). The LRM explicitly says that intermediate results need not follow the constraints of the ADT. >being that Ada is more readable/understandable/etc. than assembly. So >why is it that defining a mapping from some pre-processor to Ada is >met with such cynicism? It simply provides an additional layer of Because it is used to justify inconsistent language constructs. If I had a nickel for every time someone said, "you don't need to change the language, just use a pre-processor" I'd drown in them. Point one: any such preprocessor needs to be standardized to the level that the language is, or it defeats the purpose of the language. Point two: If such a preprocessor *is* in fact standarized to the level that the language is, there is no discernable difference between changing the language and adding a preprocessor. Point three: the argument is that assignment should not be overloadable because it is not understandable (though more readable). It makes no real difference whether you put assignment overloading into a pre-processor or into the language. The pre-processing source is what will be maintained and used. It is identically as understandable if the language is changed as it is if a processing step is added. Perhaps more so. If the language is changed, no one will *assume* that assignment cannot be overloaded. Tacking on a preprocessor is the coward's way out. >a sad commentary that there are still Ada programmers out there who >still do not understand the need for and utility of an APSE. You can It's needed because the language was designed in an inconsistant and inflexible manner in the first place. What would you say about a preprocessor that converts C into Ada. Is programming in C then as good as programming in Ada? (don't laugh, it can be done, especially if you use unchecked programming) I don't think so. Another change I'd like to see. (upward compatible this time) Allow: if A in B | C | D | Q | Y | N then ... end if; I.e. an extension of the membership idea. It's ridiculous to me that case A is when B | C => ... end case; is valid but the above (or some equivilent) is not. I argue that such a construct is both more readable and more understandable than if A = B or A = C or else ... or else A = N then ... end if; and also makes the Ada language more internally consistent. (and thus easier to use) I also argue that compiler vendors are likely to implement the former more efficiently than the latter. This is especially true when the comparands are of a large enumerated type. (hashing, and all) Anyway, enough diatribe for today. -- "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/30/88)
From article <8811282217.AA04896@ajpo.sei.cmu.edu>, by mendal@ANNA.STANFORD.EDU (Geoff Mendal): >> 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. > > I don't understand this at all. You are assuming pass by value for an > ADT? Rediculous. The LRM only states that scalars and access values > are passed by copy. In general, for an ADT, you cannot assume pass by > value and if your program depends on it, your program will execute > erroneously. This is precisely the problem. This is what must be fixed. > [Argues that the proposal would mean more work for language designers] > > [Argues that the proposal would mean more work for program provers] > > [Argues that the proposal would mean less work for him, since he > is employed as a writer of preprocessor tools for Ada] Much more money is spent using a programming language such as Ada than is spent designing it. Hence, if we can save the time of 30 million programmers at the expense of the time of 300 language designers, I submit that this is an appropriate tradeoff. What is needed is a completion of the ADT paradigm, support for which is the fundamental reason for the "limited private" feature. Given that one must remember to destroy all non-predefined ADTs upon block exit, it is clear that the implications of this paradigm were not appropriately considered in the Ada 83 design.
leake@cme-durer.ARPA (Stephe Leake) (11/30/88)
There seems to be a point of confusion concerning overloading of ":=". Some people assume that the (overloaded) semantics of ":=" apply to parameter passing. This seems to be a reasonable assumption, and I think the current Ada parameter passing semantics are equivalent to the current Ada assignment semantics. However, other types of overloading (such as for "*") only apply when the overloaded symbol appears _explicitly_; thus an argument could be made that the overloaded ":=" should only be used for explicit assignments, not the implicit ones in parameter passing. Personally, I think parameter passing should be the same as assignment, but I just wanted to point out the confusion. In Ray Trent's discussion of the Fraction Abstract Data Type, he implies that "*" and "/" do not reduce fractions to LCD form, but ":=" does. It seems to me, therefore, that he is talking about 2 data types; LCD_Fractions and Fractions. This removes the need to overload ":=". "*" and "/" take either type and return Fraction. Then, since there are two types involved, the compiler will remind maintainers to include the explicit LCD operation; A : LCD_Fraction; B, C : Fraction; A := B /C ; -- illegal A := To_LCD_Fraction (B / C); -- legal I don't think ":=" should be overloadable just so we can hide type conversions; this is one of the main complaints about C - one can never be _sure_ what type something is. The example above brings up a suggestion; type names should be overloadable by functions, so we can define type conversion functions that look like the type conversions available to scalar types. Ie the function "To_LCD_Fraction" above should be named "LCD_Fraction". I don't know which section of the LRM to refer to here; overloading rules seem very scattered. Ray Trent says: > The LRM explicitly says that intermediate > results need not follow the constraints of the ADT. Where does it say this? I second the motion for allowing: if A in (B | C | D | Q | Y | N) then ... end if; (note that I added parentheses). Currently, we can get the same effect with a subtype, but _only_ if B | C | D | Q | Y | N can be _uniquely_ described by a range constraint, which is often not the case. This is leaning further towards defining sets in Ada, something that PASCAL has always had. There are certainly problems with fully implementing sets, but I think this extension is a good one. 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
dsr@hector.UUCP (David S. Rosenblum) (12/01/88)
In article <24856@sri-unix.SRI.COM> trent@unix.sri.com (Ray Trent) writes: >In an article mendal@ANNA.STANFORD.EDU (Geoff Mendal) writes: >> >>First, assignment is NOT an operator. It is a basic operation. > >The argument is that it should be. (and is, in any sensible >(i.e. non-Ada) definition of the word operator) That there is no >reason to have "basic" operators that are "special". Most of the non-Ada definitions of "operator" that I am familiar with describe operators in a purely mathematical sense, i.e. in terms of domains and algebras. However, assignment is a concept that is peculiar to programming languages, so in a sense you're comparing apples and oranges. And most "sensible" definitions of assignment that I know of describe assignment simply in terms of placing a value in a variable or memory location. Basic operations in Ada ARE special, for very good reasons. Unlike operators, they are intimately connected with Ada's model of type constraints in some way and cannot be hidden. One of the nice features of Ada type constraints is that they are (or at least were intended to be) implemented consistently throughout the language, in part via the basic operations. This consistent enforcement would be lost if overloading of basic operations were allowed. In particular, by allowing overloading of assignment, it would be possible to override one of the fundamental steps of the assignment operation, which is to guarantee that the target variable in an assignment statement is assigned a legal value of its type. When you overload operators such as "=" and "+", you may give perverse semantics to operators that have a "traditional" meaning, but you are not able to override Ada's type checking. Thus, allowing overloading of assignment (or any basic operation) would seriously weaken Ada's strong typing features. >[lots of discussion about LCD deleted] As I understand your LCD example, you seem to see assignment overloading as a vehicle for implementing type constraints that can't be expressed in Ada's constraint language (such as LCD-ness). So why stop with assignment? Wouldn't you need overloading of all the basic operations? Suppose I'm given a language change which allows overloading of basic operations, and suppose I have a type EVEN, e.g., type EVEN is new INTEGER; which I want to constrain in a way that would require all variables of the type to have even values. In order to enforce this constraint consistently in the manner of Ada, I would want to do the following: (1) Overload := so that it raises CONSTRAINT_ERROR when given an odd right-hand-side. (2) Overload the attributes 'SUCC and 'PRED so that they skip odd values. (3) Overload the attributes 'POS and 'VAL so that count only even values. (4) Overload the attribute 'FIRST so that it returns the smallest even value of EVEN's base type. (5) Overload the attribute 'LAST so that it returns the largest even value of EVEN's base type. (6) Overload the membership tests and the ".." token so that only even ranges are considered. (7) Overload the indexing operation for all array types I define that are indexed by EVEN values, so that even-numbered components are stored and accessed contiguously. (8) Overload the aggregate operation for such array types so that the index values for the aggregate are computed "the right way". Yet after all these exertions, my evenness constraint would STILL not be enforced consistently, unless I was given several more language changes. For example, type conversions, qualifications, attribute evaluations and membership tests never propagate exceptions. Yet what would be the effect of the type conversion "EVEN(3)"? What would be the effect of the attribute evaluation "EVEN'POS(3)"? What would be the effect of the tests "2 in 0 .. 3" or "3 in 0 .. 10" ? Should they raise CONSTRAINT_ERROR, or should they round 3 to some even value? Suppose I instantiate INTEGER_IO to perform I/O on EVEN values. How do I get the instantiation to enforce my evenness constraint? First I would need another language change that requires source-level assignment "operators" to be used to implement parameter passing. But I'm still in trouble because my overloaded := cannot be made visible to my INTEGER_IO instantiation. So I would ALSO need INTEGER_IO to be redefined to accept a generic formal := parameter. Oy! I agree with Geoff. The proponents of assignment overloading have not addressed the ramifications of their proposal thoroughly enough to come up with a fully consistent change to the language. Until they do, I'm happy to write ASSIGN instead of := whenever I need a "special" assignement operation. -- David ------------------------------------------------------------------- David Rosenblum UUCP: {ucbvax, decvax}!ulysses!dsr AT&T Bell Laboratories ARPA: dsr@ulysses.att.com 600 Mountain Ave. dsr%ulysses@att.arpa Murray Hill, NJ 07974-2070 (201) 582-2906 -------------------------------------------------------------------
eachus@mitre-bedford.ARPA (Robert Eachus) (12/01/88)
There has been a lot of frothing at the mouth on both sides of this issue about what is or is not the Ada model of assignment. First of all a lot has been said about what a change to the language it would be to make assignment or other basic operations overloadable. However, if you look in 8.7 Context of Overload Resolution, the first paragraph states: "Overloading is defined for subprograms, enumeration literals, operators, and single entries, and also for the operations that are inherent in several basic operations such as assignment, membership tests, allocators, the literal null, aggregates, and string literals." Overloading, and overload resolution involving basic operations is a fact of Ada life. If you think otherwise try: package Overload_Test is type A is access Boolean; B: constant Boolean := null = null; type C is access Character; D: constant Boolean := null = null; end Overload_Test; The compiler should accept the decalartion of B, but reject the declaration of D. A lot of work went on during the language definition process to make similar (but useful) cases work for numeric types. If you object that this example involves equality which is not a basic operation instead try: package Overload_Two is A: Boolean := 'b' in 'a'..'c'; type New_Char is ('b', 'a', 'c'); C: Boolean := 'b' in 'a'..'c'; end Overload_Two;
billwolf@hubcap.clemson.edu (William Thomas Wolfe,2847,) (12/01/88)
From article <10906@ulysses.homer.nj.att.com>, by dsr@hector.UUCP (David S. Rosenblum): > One of the nice features of Ada type constraints is > that they are (or at least were intended to be) implemented consistently > throughout the language, in part via the basic operations. This consistent > enforcement would be lost if overloading of basic operations were allowed. In > particular, by allowing overloading of assignment, it would be possible to > override one of the fundamental steps of the assignment operation, which is to > guarantee that the target variable in an assignment statement is assigned a > legal value of its type. Since the overloaded assignment would be implemented in terms of the existing low-level assignment operations, I don't see where any potential problem exists here. Please clarify. > As I understand your LCD example, you seem to see assignment overloading > as a vehicle for implementing type constraints that can't be expressed in > Ada's constraint language (such as LCD-ness). > [...] > Yet after all these exertions, my evenness constraint would STILL not > be enforced consistently, unless I was given several more language changes. > For example, type conversions, qualifications, attribute evaluations and > membership tests never propagate exceptions. Yet what would be the effect > of the type conversion "EVEN(3)"? What would be the effect of the attribute > evaluation "EVEN'POS(3)"? What would be the effect of the tests > "2 in 0 .. 3" or "3 in 0 .. 10" ? Should they raise CONSTRAINT_ERROR, or > should they round 3 to some even value? The problems mentioned pertain specifically to this implementation only; if EVEN were implemented as a limited private type within an appropriate package, all the operations mentioned would be available only through the procedures/functions provided. Type conversions would not be legally expressible in the usual notation, most attributes would not be defined, etc. Ada 83 allows us to do all of these things, but not in the "conventional" notation. Since Ada does not allow implicit type conversions, the fact that we cannot overload type conversion does not cause us any grief in the parameter-passing process. Nor do any of the other operations mentioned. Only assignment and destruction play vital roles in the evaluation of parameters and in the creation and destruction of variables (particularly with regard to block entry and exit). It is the fact that the language does not consider the impact of these mechanisms upon the ADT paradigm, mechanisms which can play havoc with our abstractions, that compels us to call for changes in the language with regard to the ability to define specific procedures for assignment and destruction which are taken into consideration by these mechanisms. > I agree with Geoff. The proponents of assignment overloading have not > addressed the ramifications of their proposal thoroughly enough to come > up with a fully consistent change to the language. It is entirely possible that given the desire of AJPO to minimize the extent of changes in the language, it will not be possible to get Ada to provide complete support for the abstract data type paradigm. Ada was explicitly intended as an interim solution, covering the range 1983..20xx, and not as "the perfect language". Perhaps for Ada it is already too late. But the issue needs to be thoroughly discussed, because it is a major area in which Ada has "missed the boat". Perhaps there is a solution which AJPO will find acceptable. We must know whether or not this is the case. If there is no hope for Ada, then we must focus on the construction of Ada's successor. Bill Wolfe wtwolfe@hubcap.clemson.edu
dsr@hector.UUCP (David S. Rosenblum) (12/01/88)
In article <3698@hubcap.UUCP> wtwolfe@hubcap.clemson.edu writes: >From article <10906@ulysses.homer.nj.att.com>, by dsr@hector.UUCP (David S. Rosenblum): >> In >> particular, by allowing overloading of assignment, it would be possible to >> override one of the fundamental steps of the assignment operation, which is to >> guarantee that the target variable in an assignment statement is assigned a >> legal value of its type. > > Since the overloaded assignment would be implemented in terms of > the existing low-level assignment operations, I don't see where any > potential problem exists here. Please clarify. Essentially, the problems arise from the characteristics of Ada's parameter passing semantics. (Or we could change those too while we're at it. :-) ) Suppose ":=" overloadings are required to have an out-mode parameter to represent the target variable. Then an overloaded ":=" on a composite type can selectively assign to some components of the target and leave other components undefined (if they were undefined prior to execution of the assignment). This cannot happen with predefined assignment to objects of a composite type (i.e., when a full composite object, not just a component of one, is given as the left-hand side). Alternatively, suppose ":=" overloadings are required to have an in out-mode parameter to represent the target variable. Then it would be impossible to assign to an undefined variable, because the variable would first be constraint-checked when it is passed in to the assignment procedure. For example, procedure CIRCUMVENT is type LCD_FORM is record NUMERATOR, DENOMINATOR : INTEGER; end record; X, Y : LCD_FORM; -- X and Y undefined. procedure ":=" (L : out LCD_FORM; R : in FLOAT) is begin if R = 0.0 then L.NUMERATOR := 0; else -- calculate LCD form. end if; end ":="; begin X := 1.5; -- X.NUMERATOR is presumably 3, X.DENOMINATOR is presumably 2. -- Y.DENOMINATOR is undefined. Y := 0.0; -- Y.DENOMINATOR is STILL undefined. end CIRCUMVENT; You can object that I didn't define ":=" "correctly" and that I stupidly failed to assign to DENOMINATOR when R is zero, but that's the whole point--I've circumvented the type checking that is inherent in predefined assignment. > >> As I understand your LCD example, you seem to see assignment overloading >> as a vehicle for implementing type constraints that can't be expressed in >> Ada's constraint language (such as LCD-ness). >> [...] >> Yet after all these exertions, my evenness constraint would STILL not >> be enforced consistently, unless I was given several more language changes. >> For example, type conversions, qualifications, attribute evaluations and >> membership tests never propagate exceptions. Yet what would be the effect >> of the type conversion "EVEN(3)"? What would be the effect of the attribute >> evaluation "EVEN'POS(3)"? What would be the effect of the tests >> "2 in 0 .. 3" or "3 in 0 .. 10" ? Should they raise CONSTRAINT_ERROR, or >> should they round 3 to some even value? > > The problems mentioned pertain specifically to this implementation > only; if EVEN were implemented as a limited private type within an > appropriate package, all the operations mentioned would be available > only through the procedures/functions provided. Type conversions > would not be legally expressible in the usual notation, most attributes > would not be defined, etc. Ada 83 allows us to do all of these things, > but not in the "conventional" notation. That's the whole point of why you don't need assignment overloading!!! You can also do assignment with limited private types, but not in the "conventional" notation. All you need to do is provide an "appropriate subprogram". > > Since Ada does not allow implicit type conversions, the fact that we > cannot overload type conversion does not cause us any grief in the > parameter-passing process. Nor do any of the other operations mentioned. You seem to be missing my point. You are trying to use an overloaded assignment operator to implement a constraint on your LCD type that can't be expressed in Ada's constraint language. I've argued that I would want the ability to overload the other basic operations so that I could implement in a consistent manner the constraints that I may dream up. You've ignored that argument and instead still seem to be harboring the belief that assignment is "different" from the other basic operations. What is so unique about assignment that it alone of all the basic operations requires special treatment? > > Only assignment and destruction play vital roles in the evaluation of > parameters and in the creation and destruction of variables (particularly > with regard to block entry and exit). It is the fact that the language > does not consider the impact of these mechanisms upon the ADT paradigm, > mechanisms which can play havoc with our abstractions, that compels us > to call for changes in the language with regard to the ability to > define specific procedures for assignment and destruction which are > taken into consideration by these mechanisms. We can argue about implicitly invoked destruction mechanisms some other time, since Ada provides no such animal. And Ada's parameter passing mechanisms are defined implicitly, beyond the reach of the programmer, as they should be (again to enforce type checking)--they have nothing to do with assignment at the source level. Regarding your assignment "abstraction", all I can offer is the suggestion that reduction to LCD form is an over-specification of what I consider to be the normal semantics of an assignment operation, and it is better left to another procedure whose sole purpose is to perform the reduction. If you define your LCD type as a limited type in a package, you can provide a NORMALIZE procedure which will achieve the desired effect. If you need to add new code later, your only recourse will be to use the NORMALIZE procedure, as there is no predefined assignment operation available to confuse you. > It is entirely possible that given the desire of AJPO to minimize the > extent of changes in the language, it will not be possible to get Ada > to provide complete support for the abstract data type paradigm. Ada > was explicitly intended as an interim solution, covering the range > 1983..20xx, and not as "the perfect language". Perhaps for Ada it is > already too late. But the issue needs to be thoroughly discussed, > because it is a major area in which Ada has "missed the boat". I tend to agree with your last comment. But Ada's abstraction mechanisms will never be improved in the next revision without a proposal that is carefully thought out and is fully consistent with the goals of the language. As I've tried to illustrate, none of the proposals I've seen for assignment overloading come close to meeting these criteria. ------------------------------------------------------------------- David Rosenblum UUCP: {ucbvax, decvax}!ulysses!dsr AT&T Bell Laboratories ARPA: dsr@ulysses.att.com 600 Mountain Ave. dsr%ulysses@att.arpa Murray Hill, NJ 07974-2070 (201) 582-2906 -------------------------------------------------------------------
billwolf@hubcap.clemson.edu (William Thomas Wolfe,2847,) (12/01/88)
From article <10913@ulysses.homer.nj.att.com>, by dsr@hector.UUCP (David S. Rosenblum): > Alternatively, suppose ":=" overloadings are required to have an in out-mode > parameter to represent the target variable. Then it would be impossible > to assign to an undefined variable, because the variable would first be > constraint-checked when it is passed in to the assignment procedure. This is a question which applies to any assignment procedure, whether ":=" or "ASSIGN". The way I do it is to use in-out mode and implement the ADT as a pointer to a descriptor. That way, I take advantage of the fact that all pointers are automatically initialized to null, and I use the null-pointer state as the "empty" or "undefined" state of my ADT. I'd prefer that all data types were automatically initialized to "undefined", so I could save the space and time associated with the pointer, but the workaround does get the job done. >> The problems mentioned pertain specifically to this implementation >> only; if EVEN were implemented as a limited private type within an >> appropriate package, all the operations mentioned would be available >> only through the procedures/functions provided. Type conversions >> would not be legally expressible in the usual notation, most attributes >> would not be defined, etc. Ada 83 allows us to do all of these things, >> but not in the "conventional" notation. > > That's the whole point of why you don't need assignment overloading!!! > You can also do assignment with limited private types, but not in the > "conventional" notation. All you need to do is provide an "appropriate > subprogram". Yes, I've been doing exactly that for a long time now. >> Only assignment and destruction play vital roles in the evaluation of >> parameters and in the creation and destruction of variables (particularly >> with regard to block entry and exit). It is the fact that the language >> does not consider the impact of these mechanisms upon the ADT paradigm, >> mechanisms which can play havoc with our abstractions, that compels us >> to call for changes in the language with regard to the ability to >> define specific procedures for assignment and destruction which are >> taken into consideration by these mechanisms. > > We can argue about implicitly invoked destruction mechanisms some other time, > since Ada provides no such animal. And Ada's parameter passing mechanisms > are defined implicitly, beyond the reach of the programmer, as they should > be (again to enforce type checking)--they have nothing to do with assignment > at the source level. Regarding your assignment "abstraction", all I can > offer is the suggestion that reduction to LCD form is an over-specification > of what I consider to be the normal semantics of an assignment operation, > and it is better left to another procedure [...] The LCD example is not mine, and I'll leave it to the author of the example to make whatever counterpoints are appropriate. But with regard to the point concerning enforcement of type checking, I'd like to point out that the example you gave was one in which you did NOT define an ADT; all you did was define a local record type. I made the suggestion earlier that the definition of assignment, comparison, and other operators be restricted to the package specification in which the (limited) private ADT type was defined. The intent was to prohibit the implementation of an assignment operator over some limited private type declared somewhere else (e.g., TEXT_IO.FILE_TYPE). Another point: the ADT-handling package could leave the denominator as an undefined integer if it jolly well felt like it, as long as it met the requirements imposed by the package specification. I don't see how that would constitute any violation of type checking. >> It is entirely possible that given the desire of AJPO to minimize the >> extent of changes in the language, it will not be possible to get Ada >> to provide complete support for the abstract data type paradigm. Ada >> was explicitly intended as an interim solution, covering the range >> 1983..20xx, and not as "the perfect language". Perhaps for Ada it is >> already too late. But the issue needs to be thoroughly discussed, >> because it is a major area in which Ada has "missed the boat". > > I tend to agree with your last comment. But Ada's abstraction mechanisms > will never be improved in the next revision without a proposal that is > carefully thought out and is fully consistent with the goals of the > language. As I've tried to illustrate, none of the proposals I've seen > for assignment overloading come close to meeting these criteria. I think providing complete support for the abstract data type paradigm is fully consistent with the goals of the language; as for carefully thought out proposals, a major purpose of this discussion is to uncover bugs in the details of the proposal prior to filing the 9X revision forms (which were made available by AJPO at Tri-Ada '88). The points that have been made by you and others have done that. Whether the finalized request will be within AJPO's tolerance for change is, of course, still very much an open question. But in this language or the next, the abstraction mechanisms available to programmers will be significantly stronger as a result. Bill Wolfe wtwolfe@hubcap.clemson.edu
dsr@hector.UUCP (David S. Rosenblum) (12/01/88)
In article <755@marvin.cme-durer.ARPA> leake@cme-durer.ARPA (Stephe Leake) writes: > >There seems to be a point of confusion concerning overloading of ":=". >Some people assume that the (overloaded) semantics of ":=" apply to >parameter passing. This seems to be a reasonable assumption, and I >think the current Ada parameter passing semantics are equivalent to >the current Ada assignment semantics. They are not the least bit equivalent, for several reasons. The most obvious reason is that an implementation is free to pass composite parameters by reference, although no implementation can "assign by reference". No source-level assignment operation is "invoked" to achieve parameter passing. Parameter passing is a language facility that is implemented by the compiler, just as is, say, looping. >However, other types of >overloading (such as for "*") only apply when the overloaded symbol >appears _explicitly_; thus an argument could be made that the >overloaded ":=" should only be used for explicit assignments, not the >implicit ones in parameter passing. Personally, I think parameter >passing should be the same as assignment, but I just wanted to point >out the confusion. I personally believe such an interpretation of parameter passing creates more confusion instead of less. In essence, this interpretation adds yet another special case to the scope and visibility rules--it allows a subprogram call to "see past" a visible redefinition of assignment to a predefined one that has been hidden. >A : LCD_Fraction; >B, C : Fraction; > >A := B /C ; -- illegal >A := To_LCD_Fraction (B / C); -- legal > >The example above brings up a suggestion; type names should be >overloadable by functions, so we can define type conversion functions >that look like the type conversions available to scalar types. As I argued in the case of assignment, overloading of type conversion is overloading of a basic operation, and such a facility would allow one to circumvent type checking. As you suggested above, we don't want to turn Ada into C. ------------------------------------------------------------------- David Rosenblum UUCP: {ucbvax, decvax}!ulysses!dsr AT&T Bell Laboratories ARPA: dsr@ulysses.att.com 600 Mountain Ave. dsr%ulysses@att.arpa Murray Hill, NJ 07974-2070 (201) 582-2906 -------------------------------------------------------------------
dsr@hector.UUCP (David S. Rosenblum) (12/01/88)
In article <3702@hubcap.UUCP> wtwolfe@hubcap.clemson.edu writes: >From article <10913@ulysses.homer.nj.att.com>, by dsr@hector.UUCP (David S. Rosenblum): > > The LCD example is not mine, and I'll leave it to the author of the > example to make whatever counterpoints are appropriate. But with regard > to the point concerning enforcement of type checking, I'd like to point > out that the example you gave was one in which you did NOT define an ADT; > all you did was define a local record type. I constructed the example that way for clarity. The arguments are just as valid if I make the type private in some package. The declared objects would still be undefined, and the assignment of 0.0 would still leave a component undefined. Your suggestion of implementing ADTs as access types gets around the problems I mentioned with parameter passing, but allowing overloading of assignment then requires a great deal of faith (misguided in my view) in the programmer to implement his or her ADTs in such a safe manner. I guess you could argue that many other language features have a similarly implicit faith in the sanity of the programmer. > Another point: the ADT-handling package > could leave the denominator as an undefined integer if it jolly well > felt like it, as long as it met the requirements imposed by the package > specification. I don't see how that would constitute any violation of > type checking. The ADT-handling package may feel like leaving a component undefined, but Ada doesn't feel like leaving variables undefined after an assignment. That's why such a user-defined assignment violates Ada's strong typing. ------------------------------------------------------------------- David Rosenblum UUCP: {ucbvax, decvax}!ulysses!dsr AT&T Bell Laboratories ARPA: dsr@ulysses.att.com 600 Mountain Ave. dsr%ulysses@att.arpa Murray Hill, NJ 07974-2070 (201) 582-2906 -------------------------------------------------------------------
trent@unix.SRI.COM (Ray Trent) (12/02/88)
In an article dsr@hector.UUCP (David S. Rosenblum) writes: >domains and algebras. However, assignment is a concept that is peculiar to >programming languages, so in a sense you're comparing apples and oranges. Untrue. "Let S = foo" is an idea from mathematics. But this is an aside. >And most "sensible" definitions of assignment that I know of describe >assignment simply in terms of placing a value in a variable or memory Except C's definition, of course, which is that = is an operator that returns a value and has a domain and range. >meaning, but you are not able to override Ada's type checking. Thus, >allowing overloading of assignment (or any basic operation) would seriously >weaken Ada's strong typing features. I'm afraid unchecked programming already does that. If the language designers were sooooo concerned about strong typing, why was unchecked programming included at all? Was it perhaps because programmers know that strong typing is a crock? I'd rather have nastiness like non-strong typing out in the open, rather than hidden away in places where it can't necessarily be found. (like package bodies, for example) >Ada's constraint language (such as LCD-ness). So why stop with assignment? >Wouldn't you need overloading of all the basic operations? Suppose Of course you would. (and do) > type EVEN is new INTEGER; >which I want to constrain in a way that would require all variables of >the type to have even values. In order to enforce this constraint [several other basic operations overloaded] >For example, type conversions, qualifications, attribute evaluations and >membership tests never propagate exceptions. Yet what would be the effect And why not? They often should. >perform I/O on EVEN values. How do I get the instantiation to enforce my >evenness constraint? First I would need another language change that requires You shouldn't have to in a language that purports to have strong typing. Simply using a value outside of the constraints of the ADT should raise a constraint error. I don't actually propose we change the language to allow assignment overloading. It would cause too many problems at this late date. I'm just saying it wasn't designed right the first time. I would argue that if assignment cannot be overloaded in any situation then "=" should not be overloadable in any situation. In fact, I think it's inconsistant to allow overloading of any kind if you don't allow overloading of all kinds. After all, it's just as easy to type "FooReal(X)" and "FooInt(X)" as it is to type just "Foo(X)", right? hurm. And more understandable, right? Might even be more readable, neh? Not allowing ":=" to be overloaded because it's "special" is a kludge. -- "Our little lives get complicated It's a simple thing Simple as a flower And that's a complicated thing" ../ray\..
trent@unix.SRI.COM (Ray Trent) (12/02/88)
In the above article leake@cme-durer.ARPA (Stephe Leake) writes: >does. It seems to me, therefore, that he is talking about 2 data >types; LCD_Fractions and Fractions. This removes the need to overload Indeed, this is the case. I explained that type Fraction was not a particularly good example, and why I used it anyway. I mostly object to the internal inconsistancies of Ada...exceptions to the rules for "special" operators, the non-object status of certain types of procedural objects and not others, disallowing user definition of attributes, the wierdnesses inherent in the "use" clause that make it almost useless, the fact that Ada is supposed to be strongly typed, but that uninitialized variables of a type are not required to contain a valid value in the range of that type, and are also not required to contain an *invalid* value, etc., etc. >Ray Trent says: > > The LRM explicitly says that intermediate > > results need not follow the constraints of the ADT. >Where does it say this? LRM 11.6 [6] states: Similarly, additional freedom is left to an implementation for the evaluation of numeric simple expressions. For the evaluation of a predefined operation, an implementation is allowed to use the operation of a type that has a range wider than that of the base type of the operands, provided that this delivers the exact result, even if some intermediate results lie outside the range of the base type. They only explicitly allow this for predefined operations, though it's ambiguous enough that vendors are likely to allow it for user-defined operations as well. (and it's kind of hard to test) I object to "special" properties of language constructs that I am not "allowed" as a programmer to use or duplicate in my own types, subprograms, etc., in any event. -- "Our little lives get complicated It's a simple thing Simple as a flower And that's a complicated thing" ../ray\..
dsr@hector.UUCP (David S. Rosenblum) (12/02/88)
In article <24922@sri-unix.SRI.COM> trent@unix.sri.com (Ray Trent) writes: >In an article dsr@hector.UUCP (David S. Rosenblum) writes: >>domains and algebras. However, assignment is a concept that is peculiar to >>programming languages, so in a sense you're comparing apples and oranges. > >Untrue. "Let S = foo" is an idea from mathematics. But this is an aside. This is NOT assignment as we know it in programming languages. You don't later assign new values to S, there is no "storage" of foo in S, etc. Your expression is simply a use of the equality relation to state an assumption or axiom. You are guaranteed from the substitutivity of equality that ALL subsequent occurrences of S may be replaced by "foo". Substitutivity of this kind is not a property of assignment. >>And most "sensible" definitions of assignment that I know of describe >>assignment simply in terms of placing a value in a variable or memory > >Except C's definition, of course, which is that = is an operator that >returns a value and has a domain and range. Yes, assignment in C is an operator. And you've just justified further the argument that Ada's assignment is NOT an operator, since it returns no value. It's seems silly to use such high-falutin' terms as "domain" and "range" to describe assignment in C though, because due to C's weak enforcement of type constraints, assignment can operate on arbitrary unions of domains. >>meaning, but you are not able to override Ada's type checking. Thus, >>allowing overloading of assignment (or any basic operation) would seriously >>weaken Ada's strong typing features. > >I'm afraid unchecked programming already does that. If the language >designers were sooooo concerned about strong typing, why was unchecked >programming included at all? Was it perhaps because programmers know >that strong typing is a crock? I'd rather have nastiness like non-strong >typing out in the open, rather than hidden away in places where it >can't necessarily be found. (like package bodies, for example) Yes, unchecked programming is provided in the language, but its use is heavily discouraged. The semantics of unchecked programming are largely left to the discretion of the implementor, therefore making unchecked programming a highly non-portable feature of the language. And note the following (admittedly difficult-to-enforce) admonition in the LRM: "Whenever unchecked conversions are used, it is the programmer's responsibility to ensure that these conversions maintain the properties that are guaranteed by the language for objects of the target type. Programs that violate these properties by means of unchecked conversions are erroneous." (Book 13, Chapter 10.2, Verse 3). "Correct use" of Ada demands a good faith effort to construct portable programs. (Pardon the weasel wording.) If you believe strong typing to be a crock (and I'm one programmer that DOESN'T "know" that it's a crock), then why are you lamenting the unsatisfactory character of Ada's abstraction mechanisms? (Maybe you never said this; I'm getting confused as to who has argued what.) C gives you all the "abstraction" mechanisms you seem to desire--a wide open window to the implementation details of your data types. We seem to be getting away from the subject. Somebody has suggested allowing overloading of assignment in Ada. I have been arguing against this proposal from the hypothetical viewpoint of a person in charge of updating the language. Arguments about some of Ada's fundamental language philosophies seem out of place in this context. >I'm just saying it [assignment] wasn't designed right the first time. I would >argue that if assignment cannot be overloaded in any situation then >"=" should not be overloadable in any situation. In fact, I think >it's inconsistant to allow overloading of any kind if you don't allow >overloading of all kinds. This seems like an arbitrary argument. Overloading of operators (in the Ada sense) seems justifiable, since the operators aren't directly concerned with the semantics of strong typing. You can give kooky semantics to your favorite mathematical operator, but those semantics may be characteristic of an abstraction. However, overloading of Ada's basic operations does not seem justifiable, because they are intimately concerned with the implementation of strong typing. ------------------------------------------------------------------- David Rosenblum UUCP: {ucbvax, decvax}!ulysses!dsr AT&T Bell Laboratories ARPA: dsr@ulysses.att.com 600 Mountain Ave. dsr%ulysses@att.arpa Murray Hill, NJ 07974-2070 (201) 582-2906 -------------------------------------------------------------------
dsr@hector.UUCP (David S. Rosenblum) (12/02/88)
In article <42334@linus.UUCP> eachus@mbunix.mitre.org (Robert I. Eachus) writes: | | "Overloading is defined for subprograms, enumeration literals, |operators, and single entries, and also for the operations that are |inherent in several basic operations such as assignment, membership |tests, allocators, the literal null, aggregates, and string literals." | | Overloading, and overload resolution involving basic operations |is a fact of Ada life. Yes, but there is an important difference between overloading of operators, subprograms, etc., and overloading of basic operations. Overloaded basic operations are ALWAYS implicitly defined--they can NEVER be user-defined. It is the proposal to allow user-defined overloadings of basic operations that is prompting all the "frothing". ------------------------------------------------------------------- David Rosenblum UUCP: {ucbvax, decvax}!ulysses!dsr AT&T Bell Laboratories ARPA: dsr@ulysses.att.com 600 Mountain Ave. dsr%ulysses@att.arpa Murray Hill, NJ 07974-2070 (201) 582-2906 -------------------------------------------------------------------
billwolf@hubcap.clemson.edu (William Thomas Wolfe,2847,) (12/03/88)
From article <10918@ulysses.homer.nj.att.com>, by dsr@hector.UUCP (David S. Rosenblum): > > The ADT-handling package may feel like leaving a component undefined, but > Ada doesn't feel like leaving variables undefined after an assignment. > That's why such a user-defined assignment violates Ada's strong typing. Really? Consider the following: procedure FUN_WITH_UNDEFINED_VARIABLES is A : INTEGER; -- A is undefined... B : INTEGER; -- B is undefined... begin A := B; -- Quick, what value does A have? end FUN_WITH_UNDEFINED_VARIABLES; This compiles and executes under Alsys Ada.
adolph@ssc-vax.UUCP (Mark C. Adolph) (12/03/88)
In article <24856@sri-unix.SRI.COM>, trent@unix.SRI.COM (Ray Trent) writes: > The LRM explicitly says that intermediate > results need not follow the constraints of the ADT. Could you cite this in the LRM? This could be a very important point for we who are trying to model physical quantities (length, temperature, density, etc.) as derived types and trying to do operations on these types. -- -- Mark A. ...uw-beaver!ssc-vax!adolph
billwolf@hubcap.clemson.edu (William Thomas Wolfe,2847,) (12/03/88)
From article <10917@ulysses.homer.nj.att.com>, by dsr@hector.UUCP (David S. Rosenblum): > In article <755@marvin.cme-durer.ARPA> leake@cme-durer.ARPA (Stephe Leake) writes: >> >>There seems to be a point of confusion concerning overloading of ":=". >>Some people assume that the (overloaded) semantics of ":=" apply to >>parameter passing. This seems to be a reasonable assumption, and I >>think the current Ada parameter passing semantics are equivalent to >>the current Ada assignment semantics. > > They are not the least bit equivalent, for several reasons. The most > obvious reason is that an implementation is free to pass composite > parameters by reference, although no implementation can "assign by > reference". Sure, for "in out" mode. But for modes "in" and "out", failure to use the ADT's assignment procedure causes major problems: "out" mode: Programmer assigns the parameter a value, and the value is copied back to the actual parameter. Unfortunately, the portions of the actual parameter which were formerly accessible by pointers are now uncollectable garbage. "in" mode: Programmer assumes that this is a "pass by value" and makes modifications. Since ADT contains pointers, modification echoes through to the actual parameter. Programmer could also invoke DESTROY, blowing away major portions of the actual parameter.
sommar@enea.se (Erland Sommarskog) (12/04/88)
Geoff Mendal (mendal@ANNA.STANFORD.EDU) writes: >>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. > >Quite the contrary. The whole idea of a pre-processor or translation >tool is to remove the need to "read" the processed version. How many >... >So why is it that defining a mapping from some pre-processor to Ada is >met with such cynicism? It simply provides an additional layer of >abstraction, Pre-processors are OK, if they don't appear to you as pre-processors. For example you must make the debugger to work on the original code, not what the pre-processor produces. Also, the pre-processor should be genrally available, or else you will lose portability. Many of Geoff Mendal's ideas are reasonable. Yet, I like to provide some examples you might long for an overloadable ":=". When we declare our variables in blocks we often initiate them. This makes us feel safe, we know that the variable has a defined value, and we can deduce so by looking at the declaration part. Since ":=" is not overloadable, we cannot initiate a limited private type in a declaration. E.g. (Text is from the Text_handler in 7.6 of the LRM.) A : Text := To_text("Test string"); is illegal. My other point concerns generic parameters. I once wrote a generic package for sorted binary trees. It's parameter list looks like this: Generic Type Data_type is limited private; With procedure Assign(A : in out Data_type; B : in Data_type); With function "<"(A, B : Data_type) return boolean is <>; With function ">"(A, B : Data_type) return boolean is <>; Package Binary_trees is With an overloadable ":=" I could have declared the second parameter as With procedure ":="(A : in out Data_type; B : in Data_type) is <>; This would save the user from declaring unnecessary Assign for types like integer. This Assign procedure he has to write is simple, but is 100% noise to his code. (Of course I could make Data_type Private only, but in this case the user would be unnecessarily restriced, since he would be able to instantiate it for limited types.) Again this was some examples since Geoff Mendall wanted some. None of them shows that you "must" have overloadable ":=". Just some case there it would be nice. Oh, someone thought that an user-defined ":=" should apply to parameter passing as well. This is of course impossible. In that case ":=" should define how the parameters were passed to itself. A true circular definition! -- Erland Sommarskog ENEA Data, Stockholm sommar@enea.se "Frequently, unexpected errors are entirely unpredictable" - Digital Equipment
sommar@enea.se (Erland Sommarskog) (12/04/88)
William Thomas Wolfe (billwolf@hubcap.clemson.edu) writes: > What is needed is a completion of the ADT paradigm, support for > which is the fundamental reason for the "limited private" feature. > Given that one must remember to destroy all non-predefined ADTs > upon block exit, it is clear that the implications of this paradigm > were not appropriately considered in the Ada 83 design. With other words, what you want is garbage collection. I'm quite sure that the language designers knew about. Simula has had since 1967. Note that the language definition in no way forbids garbage collection, but it does not require it. It says: 4.8(7) "An implementation may (but need not) reclaim the storage occupied by an object created by an allocator, once this object has become inaccessible". In practice this means you must do all deallocating explictly if you want to be partable. I think the reason why garbage collection is not required is that in some applications this is not very desireable from the point of view or performance. Typically you may not want it embedded real-time systems... Another thing is of course the implementation issue... But as you point out, this is an important concept when implementing abstract data types. I think that Ada should require garbage collection and a pragma with which you could turn it off for critical code. -- Erland Sommarskog ENEA Data, Stockholm sommar@enea.se "Frequently, unexpected errors are entirely unpredictable" - Digital Equipment
billwolf@hubcap.clemson.edu (William Thomas Wolfe,2847,) (12/05/88)
From article <4123@enea.se>, by sommar@enea.se (Erland Sommarskog): > Oh, someone thought that an user-defined ":=" should apply to parameter > passing as well. This is of course impossible. In that case ":=" should > define how the parameters were passed to itself. A true circular definition! Recall the discussion. The rule that the "old" version of assign would apply throughout any function named ":=", including parameter passing, handles this contingency.
billwolf@hubcap.clemson.edu (William Thomas Wolfe,2847,) (12/05/88)
From article <4125@enea.se>, by sommar@enea.se (Erland Sommarskog): > William Thomas Wolfe (billwolf@hubcap.clemson.edu) writes: >> What is needed is a completion of the ADT paradigm, support for >> which is the fundamental reason for the "limited private" feature. >> Given that one must remember to destroy all non-predefined ADTs >> upon block exit, it is clear that the implications of this paradigm >> were not appropriately considered in the Ada 83 design. # # With other words, what you want is garbage collection. # [...] I think the reason why garbage collection is not required is that # in some applications this is not very desireable from the point of # view of performance. Typically you may not want it embedded real-time # systems... Another thing is of course the implementation issue... No, I do NOT want garbage collection. Since GC cannot handle the problems of circular-list garbage without outrageous time expenditures, and for all the other reasons you mentioned above, GC is NOT desirable. Furthermore, GC encourages sloppy programming. I'd be very happy to see GC explicitly PROHIBITED. Bill Wolfe wtwolfe@hubcap.clemson.edu
dsr@hector.UUCP (David S. Rosenblum) (12/05/88)
In article <3720@hubcap.UUCP> billwolf@hubcap.clemson.edu writes: |From article <10918@ulysses.homer.nj.att.com>, by dsr@hector.UUCP (David S. Rosenblum): |> |> The ADT-handling package may feel like leaving a component undefined, but |> Ada doesn't feel like leaving variables undefined after an assignment. |> That's why such a user-defined assignment violates Ada's strong typing. | | Really? Consider the following: | | procedure FUN_WITH_UNDEFINED_VARIABLES is | | A : INTEGER; -- A is undefined... | B : INTEGER; -- B is undefined... | | begin | A := B; -- Quick, what value does A have? | end FUN_WITH_UNDEFINED_VARIABLES; Easy. A has a value that satisfies the constraints on INTEGER, which implies that B does also. We splitting hairs here, but I'll give it to you--A is still undefined. Note that you're relying on INTEGER being implicitly initialized with a valid value; this is probably considered erroneous (I don't have an LRM on hand). | | This compiles and executes under Alsys Ada. I don't doubt it. Do you seriously regard this as "proof" that assignment doesn't incorporate type checking? ------------------------------------------------------------------- David Rosenblum UUCP: {ucbvax, decvax}!ulysses!dsr AT&T Bell Laboratories ARPA: dsr@ulysses.att.com 600 Mountain Ave. dsr%ulysses@att.arpa Murray Hill, NJ 07974-2070 (201) 582-2906 -------------------------------------------------------------------
dsr@hector.UUCP (David S. Rosenblum) (12/05/88)
In article <3721@hubcap.UUCP> billwolf@hubcap.clemson.edu writes: |From article <10917@ulysses.homer.nj.att.com>, by dsr@hector.UUCP (David S. Rosenblum): |> In article <755@marvin.cme-durer.ARPA> leake@cme-durer.ARPA (Stephe Leake) writes: |>> |>>There seems to be a point of confusion concerning overloading of ":=". |>>Some people assume that the (overloaded) semantics of ":=" apply to |>>parameter passing. This seems to be a reasonable assumption, and I |>>think the current Ada parameter passing semantics are equivalent to |>>the current Ada assignment semantics. |> |> They are not the least bit equivalent, for several reasons. The most |> obvious reason is that an implementation is free to pass composite |> parameters by reference, although no implementation can "assign by |> reference". | | Sure, for "in out" mode. But for modes "in" and "out", failure to | use the ADT's assignment procedure causes major problems: | | "out" mode: Programmer assigns the parameter a value, and the | value is copied back to the actual parameter. | Unfortunately, the portions of the actual parameter | which were formerly accessible by pointers are now | uncollectable garbage. | | "in" mode: Programmer assumes that this is a "pass by value" | and makes modifications. Since ADT contains pointers, | modification echoes through to the actual parameter. | Programmer could also invoke DESTROY, blowing away | major portions of the actual parameter. I'm terribly confused. Are we still talking about Ada? With this talk about parameter passing invoking source-level assignment, I'm not so sure. I'm not sure what your "out" mode comments refer to, but maybe you're confusing what access values (pointers) can point to in Ada, or maybe you're confusing how access values are passed as parameters in Ada--access values are ALWAYS copied IN to their respective places in formal parameters, EVEN for mode "out" formals. Your "in" mode comments are also vague. First of all, "good" Ada programmers assume nothing about parameter passing behavior. Second, an access value can be passed as a parameter, in which case the language is concerned only with the access value during parameter passing, NOT with the object designated by the access value. ------------------------------------------------------------------- David Rosenblum UUCP: {ucbvax, decvax}!ulysses!dsr AT&T Bell Laboratories ARPA: dsr@ulysses.att.com 600 Mountain Ave. dsr%ulysses@att.arpa Murray Hill, NJ 07974-2070 (201) 582-2906 -------------------------------------------------------------------
billwolf@hubcap.clemson.edu (William Thomas Wolfe,2847,) (12/05/88)
From article <10960@ulysses.homer.nj.att.com>, by dsr@hector.UUCP (David S. Rosenblum): > |> They are not the least bit equivalent, for several reasons. The most > |> obvious reason is that an implementation is free to pass composite > |> parameters by reference, although no implementation can "assign by > |> reference". > | > | Sure, for "in out" mode. But for modes "in" and "out", failure to > | use the ADT's assignment procedure causes major problems: > | > | "out" mode: Programmer assigns the parameter a value, and the > | value is copied back to the actual parameter. > | Unfortunately, the portions of the actual parameter > | which were formerly accessible by pointers are now > | uncollectable garbage. > | > | "in" mode: Programmer assumes that this is a "pass by value" > | and makes modifications. Since ADT contains pointers, > | modification echoes through to the actual parameter. > | Programmer could also invoke DESTROY, blowing away > | major portions of the actual parameter. > > I'm terribly confused. Are we still talking about Ada? With this talk > about parameter passing invoking source-level assignment, I'm not so sure. > I'm not sure what your "out" mode comments refer to, but maybe you're > confusing what access values (pointers) can point to in Ada, or maybe you're > confusing how access values are passed as parameters in Ada--access values are > ALWAYS copied IN to their respective places in formal parameters, EVEN for > mode "out" formals. OK. Envision an ADT which just happens to be implemented as a pointer to a descriptor, which probably has more pointers to the "value". Now our ADT user wishes to transfer an ADT "out". The ADT user has no idea how the ADT is implemented. Now when the procedure was invoked, let's assume that the ADT supplied as an actual parameter had some value; hence, the pointer which represents the "ADT type" is not null, and in fact constitutes the only known method for accessing a substantial amount of utilized memory. Our ADT user sends the value "out", and Ada implements this by copying the value of a single pointer. The old pointer value associated with the actual parameter is lost forever, and all the stuff it pointed to is now garbage. > Your "in" mode comments are also vague. First of all, > "good" Ada programmers assume nothing about parameter passing behavior. Anything which is passed as an "in" parameter should be treatable as something which was passed in by value. Anything which is passed as an "in out" parameter should be treatable as something which was passed by reference. Anything which is passed as an "out" parameter should be treated as the target of a pass by value in the "outward" direction. If nothing can be assumed about parameter passing behavior, then parameter passing is just too vaguely defined, and needs to be clarified. > Second, an access value can be passed as a parameter, in which case the > language is concerned only with the access value during parameter passing, > NOT with the object designated by the access value. When what is being passed is known to the user as an access value, this is precisely what the programmer expects. When what is being passed is known to the user as an ADT, this sort of behavior is totally counterintuitive. It violates the abstraction. Bill Wolfe wtwolfe@hubcap.clemson.edu
billwolf@hubcap.clemson.edu (William Thomas Wolfe,2847,) (12/05/88)
From article <10959@ulysses.homer.nj.att.com>, by dsr@hector.UUCP (David S. Rosenblum): > In article <3720@hubcap.UUCP> billwolf@hubcap.clemson.edu writes: > |From article <10918@ulysses.homer.nj.att.com>, by dsr@hector.UUCP (David S. Rosenblum): > |> > |> The ADT-handling package may feel like leaving a component undefined, but > |> Ada doesn't feel like leaving variables undefined after an assignment. # |> That's why such a user-defined assignment violates Ada's strong typing. # | # | [FUN_WITH_UNDEFINED_VARIABLES] # # Easy. A has a value that satisfies the constraints on INTEGER, which % implies that B does also. We splitting hairs here, but I'll give it % to you--A is still undefined. % % Note that you're relying on INTEGER being implicitly initialized with a valid % value; this is probably considered erroneous (I don't have an LRM @ on hand). @ @ | @ | This compiles and executes under Alsys Ada. @ @ I don't doubt it. Do you seriously regard this as "proof" that assignment @ doesn't incorporate type checking? Well, you are quoted above as saying (correct me if I'm wrong...) that Ada somehow required that a variable be defined after assignment, and that a user-defined assignment such as the one you described could leave a component undefined and therefore violate strong typing. As far as I'm concerned, if we implemented your example as a user-defined ADT, the only problem that could occur would be failure of the implementor to properly respond to a request for the value of the denominator. If the implementor handles the request properly, it wouldn't matter if there were undefined components; the user can never access them anyway, and in general will never know the difference. In other words, the implementor may well view the state in which the denominator is undefined as a valid state of the ADT. I see nothing wrong with that.
ok@quintus.uucp (Richard A. O'Keefe) (12/05/88)
In article <3733@hubcap.UUCP> wtwolfe@hubcap.clemson.edu writes: > No, I do NOT want garbage collection. Since GC cannot handle the > problems of circular-list garbage without outrageous time expenditures, Are you up-to-date on this? There has been a lot of work done on GC in the last 5 years. > Furthermore, GC encourages sloppy programming. How so? Have you some data on this? I very much prefer languages with automatic storage management (Lisp, Pop, Prolog, Simula 67, SmallTalk, ...) because there is a large class of mistakes you simply can't make (e.g. referring to nonexistent storage) and the only real sacrifice in expressiveness is that it is harder to write programs which crash when a fixed-size buffer overflows (:-). It would be a service if you could elaborate on this: if I knew what sort of sloppiness was encouraged I could more effectively try to avoid it.
sommar@enea.se (Erland Sommarskog) (12/05/88)
William Thomas Wolfe (billwolf@hubcap.clemson.edu) writes: >I said: >> Oh, someone thought that an user-defined ":=" should apply to parameter >> passing as well. This is of course impossible. In that case ":=" should >> define how the parameters were passed to itself. A true circular definition! > > Recall the discussion. The rule that the "old" version of assign > would apply throughout any function named ":=", including parameter > passing, handles this contingency. So there should be one rule for passing parameters to ":=" and another to all other subprograms? That, if nothing else, shows that there is something wrong with the idea. You expect all subprograms to behave the same. What if ":=" is renamed? Should the rules change? And if ":=" calls another subprogram, what rules should be applied in this case? Unless you don't want to fill the language definition with special cases, and I don't, the idea to have a user-defined ":=" to implicitly define parameter passing seems dead. If you really want it that way you should think of some new syntactic device for defining assignment of a limited type. -- Erland Sommarskog ENEA Data, Stockholm sommar@enea.se "Frequently, unexpected errors are entirely unpredictable" - Digital Equipment
billwolf@hubcap.clemson.edu (William Thomas Wolfe,2847,) (12/05/88)
From article <808@quintus.UUCP>, by ok@quintus.uucp (Richard A. O'Keefe): > In article <3733@hubcap.UUCP> wtwolfe@hubcap.clemson.edu writes: >> No, I do NOT want garbage collection. Since GC cannot handle the >> problems of circular-list garbage without outrageous time expenditures, > > Are you up-to-date on this? There has been a lot of work done on GC in > the last 5 years. No, I'm not, but I'll bet GC still can't be done in O(n) time with regard to the number of items of garbage, with constants no greater than the overhead of a deallocation... >> Furthermore, GC encourages sloppy programming. > > It would be a service if you could elaborate on this [...] The programmer is Johnny-on-the-spot. He/she KNOWS whether or not a given object is no longer needed. All that is necessary is an indication of this fact via the command DESTROY (Unneeded_Object). If the programmer is sloppy and leaves garbage lying all over the place, the "maid" must do all the hard work of deciding what to keep and what to throw out. Furthermore, this price must be paid repeatedly at execution time. This is a heavy price to pay for not simply designing it right the first time.
dsr@hector.UUCP (David S. Rosenblum) (12/05/88)
In article <3736@hubcap.UUCP> billwolf@hubcap.clemson.edu writes: | | Well, you are quoted above as saying (correct me if I'm wrong...) that | Ada somehow required that a variable be defined after assignment, and | that a user-defined assignment such as the one you described could leave | a component undefined and therefore violate strong typing. Yes, that was an exaggeration that I am more than happy to retract. Replace that statement with "Ada doesn't feel like allowing a variable to have a value outside of its type after an assignment to the variable. Your example certainly didn't demonstrate any weaknesses in Ada's type checking semantics, which has been the real crux of the whole discussion. | | As far as I'm concerned, if we implemented your example as a user-defined | ADT, the only problem that could occur would be failure of the implementor | to properly respond to a request for the value of the denominator. If the | implementor handles the request properly, it wouldn't matter if there were | undefined components; the user can never access them anyway, and in general | will never know the difference. In other words, the implementor may well | view the state in which the denominator is undefined as a valid state of | the ADT. I see nothing wrong with that. | For the umpteenth time, the point of my example was to show that user-definable assignment is a means of circumventing type checking. I was not concerned with the mindset of the implementor or the user of the abstraction--we can talk all day about what an ideal safe programmer would do. If you find such a weak semantics for := acceptable, then you are certainly entitled to your opinion. I'm just suggesting that you'll probably never see such a semantics in Ada. I'm afraid I've exhausted whatever supply of insight I may have been able to offer on assignment overloading. I feel I've spent more space quoting the reference manual on language fundamentals than I have on arguing any substantive points. In short, Ada is not a language to consider using if you desire (1) condoned mechanisms for circumventing type checking, (2) parameter passing mechanisms defined in terms of assignment, as assignment is defined at the source level. ------------------------------------------------------------------- David Rosenblum UUCP: {ucbvax, decvax}!ulysses!dsr AT&T Bell Laboratories ARPA: dsr@ulysses.att.com 600 Mountain Ave. dsr%ulysses@att.arpa Murray Hill, NJ 07974-2070 (201) 582-2906 -------------------------------------------------------------------
dsr@hector.UUCP (David S. Rosenblum) (12/05/88)
In article <3734@hubcap.UUCP> wtwolfe@hubcap.clemson.edu writes: | OK. Envision an ADT which just happens to be implemented as a pointer | to a descriptor, which probably has more pointers to the "value". Now | our ADT user wishes to transfer an ADT "out". The ADT user has no idea | how the ADT is implemented. Now when the procedure was invoked, let's | assume that the ADT supplied as an actual parameter had some value; | hence, the pointer which represents the "ADT type" is not null, and | in fact constitutes the only known method for accessing a substantial | amount of utilized memory. Our ADT user sends the value "out", and | Ada implements this by copying the value of a single pointer. The old | pointer value associated with the actual parameter is lost forever, | and all the stuff it pointed to is now garbage. The language already has a very nice feature to handle such situations. It's called the "limited type". By implementing your ADT as a limited type, you deny the user of the ADT the ability to assign to variables and in-out and out mode parameters of the type. The only way to assign to such a parameter or variable is to pass it to a subprogram that is part of the implementation of the ADT. That subprogram can then reclaim the storage refernced by the access value if it decides to give the parameter a new value. Geoff Mendal did a nice paper on the encapsulation of storage reclamation mechanisms inside user-defined ADTs in a paper he gave at a recent SIGAda (you can get a copy from him). | Anything which is passed as an "in" parameter should be treatable as | something which was passed in by value. Anything which is passed as | an "in out" parameter should be treatable as something which was passed | by reference. Anything which is passed as an "out" parameter should | be treated as the target of a pass by value in the "outward" direction. | | If nothing can be assumed about parameter passing behavior, then | parameter passing is just too vaguely defined, and needs to be clarified. You'll have to take this up with the Ada Language Maintenance Committee. The language designers, and many Ada programmers, believe it to be as clearly defined as it needs to be so that portable programs may be written. | When what is being passed is known to the user as an access value, | this is precisely what the programmer expects. When what is being | passed is known to the user as an ADT, this sort of behavior is | totally counterintuitive. It violates the abstraction. Right. So as I said above, define the ADT as limited private, so that you (as the implementor of the ADT) can have complete control over the use of the ADT. That way the user of the ADT won't be able to violate the abstraction. Back to work. ------------------------------------------------------------------- David Rosenblum UUCP: {ucbvax, decvax}!ulysses!dsr AT&T Bell Laboratories ARPA: dsr@ulysses.att.com 600 Mountain Ave. dsr%ulysses@att.arpa Murray Hill, NJ 07974-2070 (201) 582-2906 -------------------------------------------------------------------
billwolf@hubcap.clemson.edu (William Thomas Wolfe,2847,) (12/06/88)
From article <10963@ulysses.homer.nj.att.com>, by dsr@hector.UUCP (David S. Rosenblum): @ By implementing your ADT as a limited @ type, you deny the user of the ADT the ability to assign to variables and @ in-out and out mode parameters of the type. The only way to assign # to such a parameter or variable is to pass it to a subprogram that is # part of the implementation of the ADT. That subprogram can then reclaim # the storage refernced by the access value if it decides to give the parameter # a new value. Sure, except for the circumvention of the provided ASSIGN routine which occurs every time the ADT is passed as an "in" or "out" parameter. There is no way to deny the user this particular method of circumventing your assignment routine, or even to have the compiler warn the user that a limited private ADT cannot be relied upon as a value parameter. > | When what is being passed is known to the user as an access value, > | this is precisely what the programmer expects. When what is being $ | passed is known to the user as an ADT, this sort of behavior is $ | totally counterintuitive. It violates the abstraction. $ $ Right. So as I said above, define the ADT as limited private, so that % you (as the implementor of the ADT) can have complete control over the % use of the ADT. That way the user of the ADT won't be able to violate the % abstraction. Except by way of the parameter passing mechanism.
ok@quintus.uucp (Richard A. O'Keefe) (12/06/88)
In article <3740@hubcap.UUCP> billwolf@hubcap.clemson.edu writes: >From article <808@quintus.UUCP>, by ok@quintus.uucp (Richard A. O'Keefe): >> It would be a service if you could elaborate on this [...] > The programmer is Johnny-on-the-spot. He/she KNOWS whether or not > a given object is no longer needed. All that is necessary is an > indication of this fact via the command DESTROY (Unneeded_Object). This simply isn't true. If I write a library routine which is passed some linked data structure, I may be able to tell whether my traversal of it has finished, but that leaves me with no idea whatsoever of whether I was given the last reference to it (in which case now is the time to delete it) or not. Or suppose some "object" has references to some other objects, and I DESTROY(..) the first object. Should it DESTROY(..) the other objects? In that case it may destroy things which other objects still refer to! But if it doesn't, and it held the only references to those objects, their space will not be reclaimed. Is Johnny on the spot? NO! The programmer who coded the implementation of that object has _no_idea_ how other programmers will use it. There has been quite a lot of discussion about this in comp.lang.c++ . Let me apply billwolf@hubcap's general principle to another case: The programmer is Johnny-on-the-spot. He/she KNOWS whether a given object is an integer or a float. All that is necessary is an indication of this fact via the use of + for integers and #+ for floats. We don't need any of this strong typing nonsense! Automatic storage management, like automatic operator selection, means that the programmer misses an opportunity to make a mistake. There _are_ garbage collection methods around where the overhead of garbage collection is a constant times the cost of allocation. ADA was explicitly designed not to require garbage collection. Since it was meant to be useful for real-time work, that was appropriate.
billwolf@hubcap.clemson.edu (William Thomas Wolfe,2847,) (12/07/88)
From article <812@quintus.UUCP>, by ok@quintus.uucp (Richard A. O'Keefe): > In article <3740@hubcap.UUCP> billwolf@hubcap.clemson.edu writes: >>From article <808@quintus.UUCP>, by ok@quintus.uucp (Richard A. O'Keefe): >>> It would be a service if you could elaborate on this [...] > >> The programmer is Johnny-on-the-spot. He/she KNOWS whether or not $> a given object is no longer needed. All that is necessary is an $> indication of this fact via the command DESTROY (Unneeded_Object). $ $ This simply isn't true. If I write a library routine which is passed $ some linked data structure, I may be able to tell whether my traversal $ of it has finished, but that leaves me with no idea whatsoever of $ whether I was given the last reference to it (in which case now is the $ time to delete it) or not. Whether or not the library routine should DESTROY its parameter depends on how the library routine is defined. How about a more specific example? # Or suppose some "object" has references to # some other objects, and I DESTROY(..) the first object. Should it # DESTROY(..) the other objects? In that case it may destroy things which # other objects still refer to! But if it doesn't, and it held the only # references to those objects, their space will not be reclaimed. Again, we need specifics here. I hope you aren't talking about structural sharing here, which should NEVER be seriously contemplated. % Is Johnny on the spot? NO! The programmer who coded the implementation % of that object has _no_idea_ how other programmers will use it. The implementor has no idea what *applications* the object will be used in, but has almost total control (the exceptions occur during parameter passing and block exit) over the operations of the ADT. & There _are_ garbage collection methods around where the overhead of & garbage collection is a constant times the cost of allocation. I specified O(n) with respect to the cost of each DEallocation, with the cost no higher than the overhead of doing the deallocation. This implies that the garbage collection routine has the ability to magically know the size and location of each and every piece of garbage, and has no need to examine any non-garbage.
leake@cme.nbs.gov (Stephe Leake) (12/08/88)
In article <10917@ulysses.homer.nj.att.com> dsr@hector.UUCP (David S. Rosenblum) writes:
As I argued in the case of assignment, overloading of type conversion is
overloading of a basic operation, and such a facility would allow
one to circumvent type checking. As you suggested above, we don't want
to turn Ada into C.
Type checking _cannot_ be circumvented by overloading of type
conversion! Consider:
type DEGREES is digits 6 range 0.0 .. 360.0;
type RADIANS is digits 6;
function DEGREES (Item : in RADIANS) return DEGREES
is
begin
return Item * 180.0 / PI; -- range constraint is checked!
end;
Since the underlying Ada type checking is done on the function result,
no circumvention of type checking is possible.
On the other hand, the fact that type conversion is a basic operation
is significant; allowing overloading would mean changing it to a
normal operation (is "normal" the complement of "basic"?), with
corresponding changes in visibility. As I see it, there are two gains;
first, I get to name my type conversion functions the same as the
implicit type conversions (ie DEGREES instead of TO_DEGREES). Second,
I get to hide the implicit conversion, which is appropriate in the
case of DEGREES and RADIANS. However, Ada provides limited types for
hiding purposes, so this second point is not really valid (although a
limited type seems like a lot of effort for such a simple thing,
remember that Ada was intended for maintainers, not programmers :-).
So it probably isn't worth persuing. (Sigh - one of these days I'll
have a really good idea :-).
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
leake@cme.nbs.gov (Stephe Leake) (12/08/88)
In article <24934@sri-unix.SRI.COM> trent@unix.SRI.COM (Ray Trent) writes:
... I mostly object
to the internal inconsistancies of Ada...exceptions to the rules
for "special" operators, the non-object status of certain types
of procedural objects and not others, disallowing user definition
of attributes, the wierdnesses inherent in the "use" clause that
make it almost useless, the fact that Ada is supposed to
be strongly typed, but that uninitialized variables of a type
are not required to contain a valid value in the range of that type,
and are also not required to contain an *invalid* value, etc., etc.
That is the purpose of this discussion; to find the "inconsistencies"
in Ada, and propose solutions. So far, I don't think any of the
proposed solutions are better than what we already have. Certainly Ada
is more consistent than C! Also remember that Ada is very powerful,
and is _not_ simple; things that may appear inconsistent are actually
logical consequences of this power.
LRM 11.6 [6] states: Similarly, additional freedom is left to an
implementation for the evaluation of numeric simple expressions. For
the evaluation of a predefined operation, an implementation is
allowed to use the operation of a type that has a range wider than that of
the base type of the operands, provided that this delivers the exact result,
even if some intermediate results lie outside the range of the base type.
They only explicitly allow this for predefined operations, though it's
ambiguous enough that vendors are likely to allow it for user-defined
operations as well. (and it's kind of hard to test) I object to "special"
properties of language constructs that I am not "allowed" as a programmer
to use or duplicate in my own types, subprograms, etc., in any event.
I don't see any ambiguity: "numeric simple expressions" and
"predefined operations" are very well defined, and user ADT's do not
fit the definitions!
On the other hand, I agree that this is a "special" exception to the
general rule. It has a very good justification, however; any hardware
must have only a few types (32 and 16 integers, 64 and 32 bit float,
for example) to be efficient (although I sometimes daydream about the
connection machine, where I could implement a 25 bit float if I wanted
to :-). Ada was intended to be a practical language, as well as an
abstract one. Thus compromises are sometimes necessary.
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
leake@cme.nbs.gov (Stephe Leake) (12/08/88)
In article <3734@hubcap.UUCP> billwolf@hubcap.clemson.edu (William Thomas Wolfe,2847,) writes: OK. Envision an ADT which just happens to be implemented as a pointer to a descriptor, which probably has more pointers to the "value". Now our ADT user wishes to transfer an ADT "out". The ADT user has no idea how the ADT is implemented. Now when the procedure was invoked, let's assume that the ADT supplied as an actual parameter had some value; hence, the pointer which represents the "ADT type" is not null, and in fact constitutes the only known method for accessing a substantial amount of utilized memory. Our ADT user sends the value "out", and Ada implements this by copying the value of a single pointer. The old pointer value associated with the actual parameter is lost forever, and all the stuff it pointed to is now garbage. This is precisely the reason for limited private types; only functions provide by the ADT package may have out parameters of the limited type, so the ADT programmer can ensure correct behaviour, including garbage collection and copying. This is a much simpler solution than forcing parameter passing to use the ADT assignment operator. Anything which is passed as an "in" parameter should be treatable as something which was passed in by value. Anything which is passed as an "in out" parameter should be treatable as something which was passed by reference. Anything which is passed as an "out" parameter should be treated as the target of a pass by value in the "outward" direction. If nothing can be assumed about parameter passing behavior, then parameter passing is just too vaguely defined, and needs to be clarified. The program should be independent of the choice of parameter passing implementation. (LRM 6.2 (7) says so). What can be assumed about parameter passing behaviour is precisely what the LRM says (mostly in 6.2,3,4); no more, and no less. If you want different semantics, use a limited type (and document the semantics in the package spec). > Second, an access value can be passed as a parameter, in which case the > language is concerned only with the access value during parameter passing, > NOT with the object designated by the access value. When what is being passed is known to the user as an access value, this is precisely what the programmer expects. When what is being passed is known to the user as an ADT, this sort of behavior is totally counterintuitive. It violates the abstraction. Once again, this is why limited types are available. It is up to the ADT implementor to insure that abstraction violations are not possible. This is not always easy. 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
leake@cme.nbs.gov (Stephe Leake) (12/08/88)
In article <10962@ulysses.homer.nj.att.com> dsr@hector.UUCP (David S. Rosenblum) writes:
... I feel I've spent more space quoting
the reference manual on language fundamentals than I have on arguing any
substantive points. ...
I, for one, appreciate the time and the pointers. The LRM is complex
enough that it takes discussions like this to fully educate the user.
Thanks!
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
leake@cme.nbs.gov (Stephe Leake) (12/08/88)
In article <3757@hubcap.UUCP> billwolf@hubcap.clemson.edu (William Thomas Wolfe,2847,) writes:
Sure, except for the circumvention of the provided ASSIGN routine which
occurs every time the ADT is passed as an "in" or "out" parameter.
A limited type CANNOT be passed as an out parameter!!!!
A limited type CANNOT be passed as an out parameter!!!!
(in a user routine) LRM 7.4.4 (4). Have you got the message now? And
for an in parameter, the only access to the object is thru the ADT
functions, which work as desired.
Do you have an explicit example where a limited type violates the
abstraction in the way you are discussing? If so, maybe you have found
a compiler bug.
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
dsr@hector.UUCP (David S. Rosenblum) (12/09/88)
In article <772@marvin.cme.nbs.gov> leake@cme.nbs.gov (Stephe Leake) writes: >In article <10917@ulysses.homer.nj.att.com> dsr@hector.UUCP (David S. Rosenblum) writes: > > As I argued in the case of assignment, overloading of type conversion is > overloading of a basic operation, and such a facility would allow > one to circumvent type checking. As you suggested above, we don't want > to turn Ada into C. > >Type checking _cannot_ be circumvented by overloading of type >conversion! Consider: > >type DEGREES is digits 6 range 0.0 .. 360.0; >type RADIANS is digits 6; > >function DEGREES (Item : in RADIANS) return DEGREES >is >begin > return Item * 180.0 / PI; -- range constraint is checked! >end; > >Since the underlying Ada type checking is done on the function result, >no circumvention of type checking is possible. My comment did NOT have to do with checking the constraints of the target type. I hope anybody with a minimal familiarity with Ada knows that type constraints are checked on function return values. My point was that overloading of type conversion will allow you to "covert" pointers to integers, arrays to files, tasks to widgets, etc. This is called "casting" in C, better known as "anything goes". To me such conversions are a circumvention of Ada's strong typing model. I'll try this just one more time. By allowing the overloading of basic operations, you may gain some flexibility in defining your abstractions, but this gain will be achieved only at the (to me, unjustifiable) cost of severely weakening Ada's strong typing strictures. Any proposal to increase flexibility in defining abstractions in Ada MUST ("read my lips"--MUST) conform to the fundamental language philosophies of Ada. I would suggest two promising areas for making such improvements in an "Ada-like" way. (1) Allow user-specifiable initialization and destruction routines for types. Ray Trent and Bill Wolfe have been arguing for a parameter passing semantics based on assignment. Stroustrup, in his C++ book, argues that you need initialization mechanisms, not assignment, for parameter passing, and that initialization and assignment are fundamentally different operations. Initialization routines would be appropriate for initializing parameters that are passed by copy, which (at least for scalars) is the mandated parameter passing mechanism. (2) Define a mechanism for allowing richer user-specified constraints on types, e.g. "all objects of type EVEN must have even values", or "for all objects of record type FOO, component BAR must always be greater than component BAZ". Then let Ada's inherent type checking mechanisms check these constraints automatically. In short, Ada has a very nice type checking framework. We should try to come up with proposals that improve that framework in ways that increases its flexibility without decreasing its robustness; don't just propose tacking on new language rules and band-aids that will cheaply rid you of your frustrations with the current framework. ------------------------------------------------------------------- David Rosenblum UUCP: {ucbvax, decvax}!ulysses!dsr AT&T Bell Laboratories ARPA: dsr@ulysses.att.com 600 Mountain Ave. dsr%ulysses@att.arpa Murray Hill, NJ 07974-2070 (201) 582-2906 -------------------------------------------------------------------