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=-0.8 required=5.0 tests=BAYES_00,INVALID_DATE autolearn=no autolearn_force=no version=3.4.4 Path: utzoo!mnetor!uunet!husc6!bloom-beacon!oberon!cit-vax!ucla-cs!zen!ucbvax!IBM.COM!NCOHEN From: NCOHEN@IBM.COM (Norman COHEN) Newsgroups: comp.lang.ada Subject: Restricting := versus restricting = Message-ID: <011188.105723.ncohen@ibm.com> Date: 11 Jan 88 15:57:22 GMT Sender: daemon@ucbvax.BERKELEY.EDU Organization: The ARPA Internet List-Id: I would guess that most people, upon learning about limited private types, question the apparently arbitrary linkage between assignment and equality. What surprises me is just how often in practice this linkage turns out to be appropriate, or at least innocuous. Until Robert Firth's recent message, I had assumed that some Fundamental Truth about the relationship between assignment and equality had been revealed to the Founding Fathers. What I now see is simply a fortunate coincidence that causes the linkage between restricting assignment and restricting equality to be appropriate more often than it is inappropriate. In "Ada as a Second Language," I identified four general reasons for making a type limited: 1. Because an operation on an object of the type can affect the state of some entity indirectly referenced by that object. Examples include insertion in a linked list. Language-defined types made limited for this reason include file types, whose objects indirectly reference external files, and task types, whose objects indirectly reference processes (i.e., they "designate tasks"). Predefined assignment would cause two objects to indirectly reference the same entity, so that an operation on one object of would appear to affect the other object as well. 2. Because there are multiple representations of the same abstract value. Examples include stacks, for which array representations denote the same value even if the parts of the array above the top-of-stack index have different contents; rational numbers, unless they are represented exclusively in reduced form; and any type whose values are represented as pointers to some structure, if distinct instances of the structure with identical contents can arise. 3. Because it is necessary to assert control over the initial value of a type, e.g., to initialize a flag that can be used to ensure that no object is used before it has been passed to a registration routine. A language-defined example is the requirement that internal files be passed to OPEN before they are used in data-transmitting operations. 4. Because it is necessary to perform some additional operation each time a new copy is made of a value in a type. Examples include the maintenance of reference counts or the deallocation of the old contents of the target variable in an assignment. (I have no reason to think that all reasons for using limited types are covered by these four cases. I would be eager to receive net mail from anyone who can add to this list.) Reasons 1, 3, and 4 are reasons for a type with restricted assignment. Reason 2 is a reason for a type with restricted equality. However, the various reasons for using limited types tend to overlap in practice. For example, whenever a type represented as an access type has both operations (on the access type) that modify the state of the designated variable and the possibility of two distinct access types designating variables with the same contents, both Reason 1 and Reason 2 apply. Furthermore, I have yet to see an application of Reason 4 that does not involve access types. Types for which Reason 3 applies tend to be types whose objects have complex internal states with many components, and thus for which equality is rarely an interesting operation, so equality is usually not missed when a type is made limited for Reason 3. Ada programmers begin to grumble when confronted with types for which Reason 2 applies, but Reason 1 does not. Then the need for a user-defined equality leads, for no good reason, to the need for a user-defined copying operation. The unreduced rational-number type is such a type. A user-defined ":=" would not be useful when Reason 1 applies, because the notion of indirect reference in this case is part of the type's abstract definition, not just part of its implementation. Therefore, ANY copying operation is inappropriate. In contrast, user-defined ":=" would ease the pain when Reason 2 applies but Reason 1 does not. Reason 3 is a reason for prohibiting the assignment operation in object initialization, but not for prohibiting the assignment operation in an assignment statement. (One also wants to continue prohibiting value-creating operations like catenation, aggregate formation, and allocation when Reason 3 applies.) If we agree that the user-defined procedure is invoked only by an assignment statement and not by an object initialization, a user-defined ":=" could be useful in this case, but many programmers would be confused by the prohibition of "A: Integer := B;" when "A := B;" is allowed. Finally, Reason 4 specifically assumes that there will be a user-defined copying operation. It would be preferable to call this operation ":=" rather than COPY.