!standard 3.3(13) 07-11-29 AI05-0054-2/03 !standard 13.9.1(13) !class binding interpretation 07-10-24 !status work item 07-10-24 !status received 07-10-24 !priority Low !difficulty Hard !qualifier Omission !subject Variable views of constant objects !summary Remove erroneousness associated with using access-to-variable values designating constants, so long as they originate at a point where the language provides a variable view of the constant. Revise the definition of constant objects and views to make it clear that there always is a possibility of a variable view existing. !question The current instance of a limited type can be used to obtain a variable aliased view of a (limited) constant object. Are runtime checks needed in order to prevent the modification of a constant? !recommendation No, the practice of obtaining such a variable aliased view during initialization is an existing idiom, and should be allowed to continue even if the object is declared constant. (See the discussion section for more rationale.) !wording Modify 3.3(13) as follows: An object is either a constant object or a variable object. [The value of a constant object cannot be changed between its initialization and its finalization, whereas the value of a variable object can be changed.] Similarly, a view of an object is either a constant or a variable. [All views of a constant object are constant.] {A name that statically denotes a constant object denotes a constant view. A name that statically denotes a variable object denotes a variable view.} A constant view of [a variable] {an} object cannot be used to modify [the value of the variable] {its value}. The terms constant and variable by themselves refer to constant and variable views of objects. Modify 13.9.1(13) as follows: The dereference of an access value is erroneous if it does not designate an object of an appropriate type or a subprogram with an appropriate profile, if it designates a nonexistent object, or if it is an access-to-variable value that designates a constant object{ and it did not originate from an attribute_ reference applied to a variable view of the object}. [Redundant: [Such an]{An} access value {whose dereference is erroneous} can exist, for example, because of Unchecked_Deallocation, Unchecked_Access, or Unchecked_Conversion.] AARM NOTE: We permit the use of access-to-variable values that designate constant objects so long as they originate from a variable view, such as during the initialization of a limited or controlled constant, when there exists a variable view of the object. !discussion It is always possible for an object that is declared constant to internally contain an access-to-variable component that designates a separate heap resident object, meaning that operations on the constant object can still change the state of the "overall" object. If we were to outlaw the idiom of squirreling away an access-to-variable value during the initialization of a constant (the so-called "Rosen" trick), then the programmer would be forced to allocate a separate object in the heap to hold data that needs to be updatable. This would not provide obvious benefit to anyone, since the code would be slower, take more space, and still have exactly the same external interface, namely that an operation can change the state of a "constant." One could argue this would be confusing for non-private types, since potentially visible components of a constant might be updatable, but if the type is non-private, then the semantics of its initialization should certainly be considered open to inspection as well, and the squirreling away of the access-to-variable value should be available for all to see. We use the phrase "*originate* from an attribute_reference applied to a variable view" to allow for possible type conversions after the initial '[Unchecked_]Access that created the access-to-variable value. Hopefully that is clear enough. The key thing is that you have to have a variable view at some point, or else somebody cheated. !ACATS test There should be C-Tests that an access-to-variable view of a constant object works properly. !appendix From: Tucker Taft Sent: Wednesday, October 24, 2007 11:26 AM I have attached variant 2 of AI-54 [this is version /01 of the AI - ED.], the AI dealing with the erroneousness of using an access-to-variable value designating a constant object. This variant proposes to eliminate the erroneousness, so long as the value originated from an attribute_reference applied to a variable view of the constant. Such a variable view is provided during initialization for limited and controlled objects. The basic point is that this is an existing idiom, and that disallowing it would just force programmers to allocate a separate heap object to hold data that needs to be updatable, which doesn't do anybody any favors, since you still have the same external interface, namely that an operation can apparently change the "state" of a constant. **************************************************************** From: Randy Brukardt Sent: Wednesday, October 24, 2007 8:26 PM Thanks for doing this. I'm concerned that your AI doesn't cover tasks. Obviously, tasks in constants is a new concept, and it seems that we don't have an allowance for that. task type T is entry Set (A : in Integer); entry Get (A : out Integer); end T; task body T is Val : Integer := 0; begin loop select accept Set (A : in Integer) do Val := A; end Set; or accept Get (A : out Integer) do A := Val; end Get; end select; end loop; end T; type Lim is limited record Tsk : T; end record; procedure Do_It (Obj : in Lim) is begin Obj.Tsk.Set (10); end Do_It; procedure Check_It (Obj : in Lim) is V : Integer; begin Obj.Tsk.Get (V); if V /= 10 then raise Program_Error; end if; end Check_It; declare Obj : constant Lim := (Tsk => <>); begin Do_It (Obj); Check_It (Obj); end; The call to Do_It causes a modification to the local data of the task Obj.Tsk, which is a part of a constant. This surely seems to violate 3.3(13/2) "The value of a constant object cannot be changed." (one presumes that the local values of a task are part of the value of an object containing that task). There doesn't seem to be any penalty for this violation, so maybe it is safe to ignore it, but it seems odd at best. **************************************************************** From: Tucker Taft Sent: Wednesday, October 24, 2007 9:24 PM > I'm concerned that your AI doesn't cover tasks. Obviously, tasks in > constants is a new concept, and it seems that we don't have an allowance for > that. I'm pretty surprised you are worried about this. It has been possible to call entries of task "IN" parameters since Ada 83, so I presumed we never considered the local variables of a task body as part of the "value" of a task object. > ... > > The call to Do_It causes a modification to the local data of the task > Obj.Tsk, which is a part of a constant. This surely seems to violate > 3.3(13/2) "The value of a constant object cannot be changed." Well that isn't quite what 3.3 says, it says you can't change the value between its initialization and its finalization. In any case, I think this is clearly violated by the "Rosen" trick applied to a constant. I think this AI needs to fix this paragraph as well. Perhaps as follows: An object is either a constant object or a variable object. [The value of a constant object cannot be changed between its initialization and its finalization, whereas the value of a variable object can be changed.] Similarly, a view of an object is either a constant or a variable. [All views of a constant object are constant.] {A name that statically denotes a constant object is a constant view. A name that statically denotes a variable object is a variable view.} A constant view of [a variable] {an} object cannot be used to modify [the value of the variable] {its value}. The terms constant and variable by themselves refer to constant and variable views of objects. The net effect is that "constant object" isn't a very interesting term. It basically means that its name denotes a constant view, but that there might be other views that provide a variable view of the same object. > ... (one presumes > that the local values of a task are part of the value of an object > containing that task). I don't make that presumption, and haven't since Ada 83. Perhaps a NOTE to that effect might be friendly. **************************************************************** From: Randy Brukardt Sent: Wednesday, October 24, 2007 9:26 PM > > I'm concerned that your AI doesn't cover tasks. Obviously, tasks in > > constants is a new concept, and it seems that we don't have an allowance for > > that. > > I'm pretty surprised you are worried about this. > It has been possible to call entries of task "IN" > parameters since Ada 83, so I presumed we never > considered the local variables of a task body > as part of the "value" of a task object. An "in" parameter is a constant view of a variable object. I'm thinking about constant objects; recall that 3.3(13/2) says that all views of a constant object are constant. There's no variable view existing anywhere, and that's what's different. Maybe it's hair-splitting. > > ... > > > > The call to Do_It causes a modification to the local data of the task > > Obj.Tsk, which is a part of a constant. This surely seems to violate > > 3.3(13/2) "The value of a constant object cannot be changed." > > Well that isn't quite what 3.3 says, it says you can't > change the value between its initialization and its > finalization. In any case, I think this is clearly > violated by the "Rosen" trick applied to a constant. > I think this AI needs to fix this paragraph as well. > Perhaps as follows: > > An object is either a constant object or a variable > object. [The value of a constant object cannot be changed > between its initialization and its finalization, whereas > the value of a variable object can be changed.] Similarly, > a view of an object is either a constant or a variable. > [All views of a constant object are constant.] {A name > that statically denotes a constant object is a constant > view. A name that statically denotes a variable object > is a variable view.} A constant view of [a variable] > {an} object cannot be used to modify [the value of the > variable] {its value}. The terms constant and variable > by themselves refer to constant and variable views of objects. > > The net effect is that "constant object" isn't a very > interesting term. It basically means that its name > denotes a constant view, but that there might be other > views that provide a variable view of the same object. That would satisfy my concern. > > ... (one presumes > > that the local values of a task are part of the value of an object > > containing that task). > > I don't make that presumption, and haven't since Ada 83. > Perhaps a NOTE to that effect might be friendly. Well, they certainly aren't part of the enclosing object in our implementation. But I can't find anything in the language semantics that says that. Just because we all think something is true does not make it true! But I do prefer your rewording of 3.3(13/2), because it will help avoid misconceptions. **************************************************************** From: Tucker Taft Sent: Wednesday, October 24, 2007 11:08 PM >> I'm pretty surprised you are worried about this. >> It has been possible to call entries of task "IN" >> parameters since Ada 83, so I presumed we never >> considered the local variables of a task body >> as part of the "value" of a task object. > > An "in" parameter is a constant view of a variable object. I'm thinking > about constant objects; recall that 3.3(13/2) says that all views of a > constant object are constant. There's no variable view existing anywhere, > and that's what's different. Maybe it's hair-splitting. But the more fundamental part of 3.3 is the part that says you can't use a constant view to modify an object. But you *can* call an entry on a constant view of a task object (even in Ada 83), so clearly calling an entry is *not* considered "modifying" a task object. Hence the local variables of a task body must clearly not be considered part of the "value" of a task object. I don't think we need any hand waving to prove that, based on semantics that have existed since Ada 83. >>> ... >>> >>> The call to Do_It causes a modification to the local data of the task >>> Obj.Tsk, which is a part of a constant. This surely seems to violate >>> 3.3(13/2) "The value of a constant object cannot be changed." >> Well that isn't quite what 3.3 says, it says you can't >> change the value between its initialization and its >> finalization. In any case, I think this is clearly >> violated by the "Rosen" trick applied to a constant. >> I think this AI needs to fix this paragraph as well. >> Perhaps as follows: >> >> An object is either a constant object or a variable >> object. [The value of a constant object cannot be changed >> between its initialization and its finalization, whereas >> the value of a variable object can be changed.] Similarly, >> a view of an object is either a constant or a variable. >> [All views of a constant object are constant.] {A name >> that statically denotes a constant object is a constant >> view. A name that statically denotes a variable object >> is a variable view.} A constant view of [a variable] >> {an} object cannot be used to modify [the value of the >> variable] {its value}. The terms constant and variable >> by themselves refer to constant and variable views of objects. >> >> The net effect is that "constant object" isn't a very >> interesting term. It basically means that its name >> denotes a constant view, but that there might be other >> views that provide a variable view of the same object. > > That would satisfy my concern. Glad to hear it. > >>> ... (one presumes >>> that the local values of a task are part of the value of an object >>> containing that task). >> I don't make that presumption, and haven't since Ada 83. >> Perhaps a NOTE to that effect might be friendly. > > Well, they certainly aren't part of the enclosing object in our > implementation. But I can't find anything in the language semantics that > says that. Just because we all think something is true does not make it > true! No, but see my rationale given above. **************************************************************** From: Jean-Pierre Rosen Sent: Thursday, October 25, 2007 7:27 AM > The call to Do_It causes a modification to the local data of the task > Obj.Tsk, which is a part of a constant. This surely seems to violate > 3.3(13/2) "The value of a constant object cannot be changed." (one presumes > that the local values of a task are part of the value of an object > containing that task). > > There doesn't seem to be any penalty for this violation, so maybe it is safe > to ignore it, but it seems odd at best. Well, a constant can include a pointer to a variable, whose value can also be changed. Not exactly the same thing, but I think close enough that we don't have to care about it. **************************************************************** From: Erhard Ploedereder Sent: Sunday, February 3, 2008 6:29 PM My original intent to constrain legitimizing assignments to constants via the Rosen trick to constants of private type fell prey to generic contract issues, as the minutes already opined. (Or else I would have to impose so much load on implementing the variable-views-to-constants that the proposal would be flat on its face anyhow). Instead of revising AI-54 in ways that have not been discussed at a meeting, I am submitting a comment on the AI, since I have several issues with this AI-54/02..... The modification of 3.3(14) with its new notion of "updating a variable" may be technically opportune (and work), but it violates the "least surprise" principle of language design. "If the value of a variable changes by any operation, the variable has been updated" is something that 100% of computer scientists will sign as a true statement. It would no longer hold in Ada. Instead, the notion that "updating a variable" by assignment is dependent on the view of the type of a component whose value is changed is completely counter to the common interpretation of what updating a variable means. (Besides, I still am uncertain about all the ramification that are implied by "... the variable if its type is not a descendent of a partial view of a full or actual type"; I claim that max. 50% of the ARG and 0,x% of the Ada users understand the implications.) ---- Side remarks: 1. assuredly, this needs to say "object" instead of "variable" (or else the intended effect for the modification of constants is not achieved); 2. "its type" binds ambiguously both to "part" and "variable". ----- I fell into this trap, too, since for the longest time, I then assumed that now assigning to said excepted parts would be allowed. But no, it isn't: Assigment semantics also requires a variable view. Consider procedure Foo(X: in T) is begin null; X.M.Gen.Z := 8; -- Rosen trick; X.M.Gen is an acc-to-var view of X X.Z := 8; -- still illegal, since X is not a variable view end Foo; and assume that Obj.M.Gen is always initialized such that it self-references Obj for any Obj. Assume further that all object-declarations in the universe carry a "constant" keyword. I had a large example prepared to show how the latter assignment causes problems, but then I found out that it was illegal by this other rule in 5.2. So, let's get this straight as per the revised 3.3(14): "The first assigment does not update X, although it changes the value of the Z component of X, but it updates Z. The second assignment would change the value of the Z component of X and thus update Z and X, but it is illegal to do so." Technically correct, but changing the same component by two different syntaxes has two different semantics? That is very interesting. How does one teach that to anyone? Did you believe the first quoted statement? It actually is wrong and again, I fell into that trap. If X happens to be passed by value, then X.M.Gen.Z still refers to the Z component of the actual, while X.Z refers to the Z component of the formal copied from the actual. Only if X is passed by reference are the Zs the same (which is the case for the Rosen trick with limited or tagged types, but not necessarily any more if merely an access-to-variable of a constant has been obtained and squirreled away elsewhere, i.e., not in an access discriminant. Note that the permission to use access-to-variable views on constant objects (as per the modified 13.9.1(13)) is not restricted to limited or by-reference types. Built-in-place extended results as initializations of constants are a case in point. They need not be limited, yet any access value obtained in the process would be legitimate. On a secondary note, this AI, if approved, would make code optimization or any program analyses incorrect that assume equal values of a constant entity at all places after its declaration. This is completely counter-intuitive and may require major compiler, analyzer and backend reworks, let alone rewiring of people's brains. For every one of these three reasons, a different way to legitimize the Rosen trick needs to be found if legitimizing is really desirable. (Personally, I find the conceptual and real costs of legitimizing the idiom much too high in anything that I have seen so far.) note bene: I am not opposed to making the constant/variable view notion more explicit, as it is done with the 3.3(13) rewrite and with the add-on after 3.3(14). I am merely opposed to have constant views that somehow can be perverted into lasting variable views (and dead set against perverting notions like "updating a variable" to special needs). --- Another side remark --- If the add-on after 3.3(14) is kept in the final AI, it also needs to mention Pragma Volatile on constants as an exception. --------------------------- Solutions ?: One possibility is to "upgrade" the access-to-variable modification of a constant to be a bounded error rather than erroneous: For subsequent uses of the constant either the assigned value or the old value is used. While not a deterministic semantics, it gets rid of the erroneousness. It also reflects the "actual events" of today, i.e., the cacheing of constant values at compile- or runtime. **************************************************************** From: Randy Brukardt Sent: Monday, February 4, 2008 11:06 PM ... Instead of revising AI-54 in ways that > have not been discussed at a meeting, I am submitting a comment on the AI, > since I have several issues with this AI-54/02..... > > The modification of 3.3(14) with its new notion of "updating a variable" may > be technically opportune (and work), but it violates the "least surprise" > principle of language design. Huh? There is no modification to 3.3(14) in any latest version of AI05-0054-1 or AI05-0054-2. And I don't see any way that the proposed change to 3.3(13) would have any effect. Ada has always had constant views of variable objects, so nothing new there. >"If the value of a variable changes by any operation, the variable has been > updated" is something that 100% of computer scientists will sign as a true > statement. It would no longer hold in Ada. Instead, the notion that > "updating a variable" by assignment is dependent on the view of the type > of a component whose value is changed is completely counter to the > common interpretation of what updating a variable > means. (Besides, I still am uncertain about all the ramification that are > implied by "... the variable if its type is not a descendent of a partial > view of a full or actual type"; I claim that max. 50% of the ARG and 0,x% of > the Ada users understand the implications.) This makes no sense. There is no wording like "... the variable if its type is not a descendent of a partial view of a full or actual type" in any of the AIs. What are you reading??? ... > note bene: I am not opposed to making the constant/variable view notion > more explicit, as it is done with the 3.3(13) rewrite and with the add-on > after 3.3(14). I am merely opposed to have constant views that somehow can > be perverted into lasting variable views (and dead set against perverting > notions like "updating a variable" to special needs). There is no "add-on after 3.3(14)" in any version of the AI that I've seen. Perhaps that is adding confusion where none is necessary... **************************************************************** From: Tucker Taft Sent: Monday, February 4, 2008 11:40 PM I'll admit I didn't follow all of what Erhard wrote, but I agree that we should change the second sentence of 3.3(14) as follows: ... The value of [a variable] {an object} is updated when an assignment is performed to any part of the [variable] {object}, or when an assignment is performed to an enclosing object. ****************************************************************