From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,4b06f8f15f01a568 X-Google-Attributes: gid103376,public From: Matthew Heaney Subject: Re: Software landmines (was: Why C++ is successful) Date: 1998/09/16 Message-ID: X-Deja-AN: 391629042 Sender: matt@mheaney.ni.net References: <6rnhhe$e2u$1@nnrp1.dejanews.com> <6rsg0d$pcj@dfw-ixnews3.ix.netcom.com> <6s6v4i$mht@dfw-ixnews8.ix.netcom.com> <35F377B2.456C6374@sprintmail.com> <35F3FF42.D1E163E0@elca-matrix.ch> <6t1b6o$ldk$1@nnrp1.dejanews.com> NNTP-Posting-Date: Wed, 16 Sep 1998 00:42:27 PDT Newsgroups: comp.lang.ada Date: 1998-09-16T00:00:00+00:00 List-Id: dewarr@my-dejanews.com writes: > > > > declare > > > > A : Integer renames Get_A (10); > > > > B : Float renames Get_B (X); > > > > C : Boolean renames Get_C (Y); > > > > begin > > > > Op (A, B, C); > > > > end; > I must say that I find the renaming of function calls > like this to be a confusing oddity. It seems much clearer > to me to use ordinary constant declarations. The two > seem completely equivalent! Funny, since using Ada95, I always use "renames" in preference to "constant T :=". One difference is that renames is available for limited types: declare File : File_Type renames Standard_Output; begin This nicely emphasizes that this isn't assignment: it's a binding of a name to an object, which is completely different, and justifies the different syntax. For a while now I've felt that Ada really got the concept of initialization all wrong. Dijkstra speaks to the issue in Chap 10, An Essay on the Notion: "The Scope of Variables" in his book A Displine of Programming: (start of quote) Upon second thought it seems only honest to use different notations [for initialization and assignment], for they are very different operations: while the initializing statement is in a sense a creative one (it creates a variable with an initial value), the true assignment statement is a destructive one in the sense that it destroys information, viz. the variable's former value. (end of quote) He hit the nail right on the head. The problem with Ada is that it blurs the distinction between initialization and assignment, especially since it uses the assignment operator in a constant declaration. (Although even Dijkstra used the assignment operator in his declarations. The only difference is that he marks initialization with the keyword "vir" (for "virgin"), and Ada marks it using "constant".) Robert, you pointed out in an earlier post how many programmers "misuse assignment." This is confirmed by my own experience. However, if many programmers do the wrong thing wrt a specific language construct, then that may indicate something is wrong with the language itself, and not with the programmers. The use of the assignment operator where initialization is intended tends to inculcate the idea that there really isn't any difference. This is unfortunate. One obvious problem with the Ada approach is that limited objects can't be initialized during their declaration (except for default initialization, of course). Better would have been true constructor operations, with a different syntax. In the past I've suggested something like: declare File : File_Type'Open ("matt.dat", In_File); begin so that no assignment operator is required in order to do initialization. Unfortunately, not being able to initialize a limited object during its elaboration means that there's a zone between the object declaration and object initialization, in which the state of the object may be undefined. (Or only defined via what's possible using default initialization - but that kind of initialization isn't very interesting or useful.) It also means if I build up a value in a declarative region, via a series of constant declarations, then when I reach the declaration of a limited object, I have to stop the declarative region, since I can't use the limited object until I've initialized it, which doesn't occur until the start of the exectuble region. This is a real bummer, since I have to create variables when constants would do. The assignment operator in Ada is very confusing still, because I can use it as a renames operator for a limited object that's a default parameter: procedure Op (File : File_Type := Standard_Output); Very confusing indeed, since the assignment operator is clearly not being used for assignment! I'm all for language parsimony, but this overloading of the assignment operator is only going to confuse neophytes. So if I seem inclined to use a renames clause when the language allows me to use assignment operator, it's because I'm trying to emphasize that the declaration has the sense of a binding operation, and to de-emphasize any notion of assignment. When I look at the constant declaration declare A : constant Integer := Get_A (...); begin I really have to cringe, since it looks so much like an assignment. Thinking about it more, I think that Ada unnecessarily exposed the fact that an entity is a constant object, when all a client really cares about is that it's a name bound to a value. It would have been hipper if the language allowed this to be hidden somehow, so that only the implementator of an abstraction has to know that the return value is really a constant object. It would also be more consistent with other syntactic constructs that bind a name to a value: package P is ... binds the name P to a package. procedure Op (...) is ... binds the name Op to a procedure. type T is ... bind the name T to a type. -but- declare A : constant Integer := ...; begin binds the name A to a value??? Why not a uniform syntax: declare A : Integer is ...; begin or maybe declare value A : Integer is ...; Using renames comes close to being able to do that: declare A : Integer renames ...; begin It's sort of a bummer that we have two different keywords (renames vs is) to do binding. But the language problem we really need to solve is array initialization. For example, it's sometimes required to have array components whose state is a function of their index value. If the array components are limited, then there's no simple way to do that (say, to pass in the index value as the discriminant of a task object, to serve as its Id), except by using two array declarations and indirection. One idea I had is something like: task type Task_Type (Id : Positive) is ...; type Array_Type is array (Positive range <>) of Task_Type; declare O : Array_Type (1 .. N)'(for I in O'Range O(I)); begin You could even invoke a constructor using this syntax: type CT is ...; constructor CT'Initialize (Index : Positive); type T is array (Positive range <>) of CT; declare O : T (1 .. N)'(for I in O'Range O(I)'Initialize (I)); begin