Version 1.8 of ai05s/ai05-0054-2.txt

Unformatted version of ai05s/ai05-0054-2.txt version 1.8
Other versions for file ai05s/ai05-0054-2.txt

!standard 3.3(13)          09-05-21 AI05-0054-2/06
!standard 3.3(25)
!standard 13.9.1(13)
!class binding interpretation 07-10-24
!status Amendment 201Z 08-11-26
!status WG9 Approved 09-06-12
!status ARG Approved 7-0-1 08-11-02
!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 of controlled and immutably limited types, so long as they originate at a point where the language provides an aliased variable view of the constant.
Revise the definition of constant objects and views to make it clear that there usually 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? (No.)
!recommendation
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. A similar idiom exists for controlled types using Initialize and Adjust rather than the current instance. (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 {elementary }object are constant. {All views of a constant composite object are constant, except for parts that are of controlled or immutably limited types; variable views of those parts and their subcomponents may exist. In this sense, objects of controlled and immutably limited types are inherently mutable.} 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.
Add a new NOTE after 3.3(25):
The value of a constant object cannot be changed after its initialization, except in some cases where the object has a controlled or immutably limited part (see 7.5, 7.6, and 13.9.1).
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 an aliased variable view of a controlled or immutably limited 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 (replacing 13.9.1(13.b)): We permit the use of access-to-variable values that designate constant objects so long as they originate from an aliased variable view of a controlled or immutably limited constant, such as during the initialization of a constant (both via the "current instance" and during a call to Initialize) or during an assignment (during a call to Adjust).
[Note: This wording depends on the definition of "immutably limited" from AI05-0052-1.]
!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. Moreover, we require that variable view to be aliased and originate from a controlled or immutably limited type, so that uses of 'Address and uses of Address_to_Access_Conversions are excluded from the exception (thus modifying a non-limited untagged type this way is still erroneous).
!corrigendum 3.3(13)
Replace the paragraph:
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 constant view of a variable object cannot be used to modify the value of the variable. The terms constant and variable by themselves refer to constant and variable views of objects.
by:
An object is either a constant object or a variable object. Similarly, a view of an object is either a constant or a variable. All views of a constant elementary object are constant. All views of a constant composite object are constant, except for parts that are of controlled or immutably limited types; variable views of those parts and their subcomponents may exist. In this sense, objects of controlled and immutably limited types are inherently mutable. A constant view of an object cannot be used to modify its value. The terms constant and variable by themselves refer to constant and variable views of objects.
!corrigendum 3.3(25)
Insert after the paragraph:
NOTES
5 A constant cannot be the target of an assignment operation, nor be passed as an in out or out parameter, between its initialization and finalization, if any.
the new paragraph:
6 The value of a constant object cannot be changed after its initialization, except in some cases where the object has a controlled or immutably limited part (see 7.5, 7.6, and 13.9.1).
!corrigendum 13.9.1(13)
Replace the paragraph:
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. Such an access value can exist, for example, because of Unchecked_Deallocation, Unchecked_Access, or Unchecked_Conversion.
by:
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 an aliased variable view of a controlled or immutably limited object. An access value whose dereference is erroneous can exist, for example, because of Unchecked_Deallocation, Unchecked_Access, or Unchecked_Conversion.
!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.

****************************************************************

From: Erhard Ploedereder
Sent: Wednesday, February  6, 2008  6:01 AM

> 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

I was working off a paper copy that had these mods to 3.3(14). Tracking
this back to its origins, it turns out to be a copy that I modified at the
DC meeting with results of the discussion at the time. So I was biting my
own tail.

Sorry to have caused confusion. I will rewrite the comment to refer to the
most recent recorded version of the AI. 

****************************************************************

From: Erhard Ploedereder
Sent: Friday, February  8, 2008  5:32 AM

I would like to ask for withdrawal of AI-54 from the Tampa agenda, 
since I would like to participate in its further discussion.

The arguments in the AI so far are misleading.

For example, they imply that somehow the Rosen trick is deemed erroneous
by current semantics. That's false. It is perfectly legitimate today for
most of its uses (namely, getting around the fact that an IN parameter in
some abstraction needs to have modified internal state), as long as the
actual parameter is not declared to be a constant. Note that 13.9.1(13)
does not apply in this case. It only applies if the original object behind
the views has been declared constant.
(Aside: I had not realized this before, but the Rosen trick, if it is
applied to non-limited or non-tagged types, is even resilient to the
actual parameter passing mechanism, since the acc-to-var will always
point to the original object, both in by-ref and by-val.)

Furthermore the proposed change trades the safety principle that I can trust
specifications, in this case the "constant" specification on an object
declaration, against avoiding erroneousness in a quite dubious and rare
sitation, namely the modification of said constant by the Rosen trick. This
is a REALLY BAD tradeoff, when a specification can be violated in order to
legitimate an obscure and, for constant, very dubious idiom.

It has been argued that "constant" for an object declaration does not mean
constant object, but only constant view of the object.  Today is does not,
however, and I will counterargue that this would be a HUGE upward
incompatibility plus a real design mistake.

Even if the change is not incompatible in terms of canonical execution
semantics, I can come up with examples of incompatibilities thanks to
legitimate optimizations like copy propagation, which clearly are allowed to
rely on the constantness of constants so far, but would no longer. But it is
certainly an incompatibility for any analysis or verification tool in
existence.  I do not know of any such tool that would not immediately take
advantage of asserted constantness. (Tuck, how about your tools?)

The design mistake, of course, is that the language would either loose
constants alltogether (probably true, thanks to extended return statements
and the fact that the proposed revision of 13.9.1(13) legitimizes even
Unchecked_* accesses in the case in question), or create two classes of
constant objects: the class of the real constants and the class of the 
variable constants. What a great idea.

In short, I will argue for "no action" on this AI. 
(And again, if someone really wants to get rid of erroneousness, make it
 a bounded error. But an error it is, discovered or not.)

****************************************************************

From: Edmond Schonberg
Sent: Friday, February  8, 2008  6:45 AM

> I would like to ask for withdrawal of AI-54 from the Tampa agenda,
> since I would like to participate in its further discussion.
>
> The arguments in the AI so far are misleading.

Understood. We'll postpone discussion of this one until the Venice  
meeting. (an refrain from using the Rosen trick except in dire
emergencies).

****************************************************************

From: Robert A. Duff
Sent: Monday, February 11, 2008  3:20 PM

> (Aside: I had not realized this before, but the Rosen trick, if it is
> applied to non-limited ...

The Rosen trick works only for limited types.
That is, the following:

   type T is
       record
          Self : access T := T'Unchecked_Access; -- Illegal!
       end record;

is illegal, because the current instance of a nonlimited type is not
aliased.

>...or non-tagged types, is even resilient to the
> actual parameter passing mechanism, since the acc-to-var will always
> point to the original object, both in by-ref and by-val.)

****************************************************************

From: Erhard Ploedereder
Sent: Saturday, February 16, 2008  8:02 AM

> The Rosen trick works only for limited types.

True in its original form of using an access discriminant as part of default
initializion. 
False, if "Rosen Trick" is equated with "gain an access-to-variable to a 
constant during initialisation by whatever tricky means."
AI-54 is about the latter, not the former. 

Why false? Consider the following example, where nothing in sight is
limited and yet I have variable access to a constant object. 
I give you the full compilable and runnable example...

with Ada.Finalization; use Ada.Finalization;
package ConstantsC is
   type T is private;
private
   type FatArray is array (1 .. 10000) of Integer;
   type T is new Controlled with
      record
         Z    :   Integer := 5;
         Comp :   access T;
         Weight : FatArray := (others => 1);
      end record;

   procedure Foo (X : in     T);
   procedure Adjust (X : in out T);

end ConstantsC;


with Text_IO;
package body ConstantsC is
   procedure Foo (X : in     T) is
   begin
      X.Comp.Z := 8;
   end Foo;
   
   function Inplace return T is
   begin
      return X: aliased T do
         X.Comp := X'Unchecked_Access;
      end return;
   end;

   procedure Adjust (X : in out T) is
   begin
     X.Comp := X'Unchecked_Access;
   end Adjust;

   X : constant T := Inplace;

begin
   Foo(X);
   Text_IO.Put_Line(Integer'Image(X.Z));
end ConstantsC;

with ConstantsC;
procedure TestconstantsC is
begin
   null;
end TestconstantsC;

The FatArray in the example is a relict of my (failed) attempts to
"convince" GNAT to initialize in place for a non-limited type. If that were
to happen, and I don't think that the language prohibits this optimization,
the "trick" would work even for types that are not by-reference, i.e. pretty
much any type.
In that case, there really are no more constants. 

****************************************************************

From: Edmond Schonberg
Sent: Saturday, February 16, 2008  8:38 AM

> Why false? Consider the following example, where nothing in sight is
> limited and yet I have variable access to a constant object.
> I give you the full compilable and runnable example...

Very cute!  However, AI-53 removes the "aliased" from extended return  
statements, so the example is in fact illegal.  True constants are  
safe .. for another few seconds at least.
From a more pragmatic point of view, this means that types with self- 
references cannot be treated as constants by a static analyzer,  
because in a sense they have some state. Is this such a huge loss?

****************************************************************

From: Erhard Ploedereder
Sent: Saturday, February 16, 2008  9:04 AM

Several problems: 
"types with self-references": that is an undecidable property; The "access
T" component may point to some other T object and that would be perfectly
fine in a true constant.

Moreover, it needn't be self-reference, it can be an arbitrary cycle. I can
squirrel away the access-to-variable value in some other object (I think),
maybe even one that I create during initialization for that very purpose and
that I point to.  I.e., my type has an access T2 component; T2 has an access
T component.

And finally, cries of breach of privacy. Although I can live with that one.

****************************************************************

From: Tucker Taft
Sent: Saturday, February 16, 2008  9:39 AM

I believe the only types to which this issue arises
are "immutably" limited types and controlled types,
since during their initialization, limited types
are writable and aliased from "inside" the type
declaration, while controlled types are writable
and aliased from "inside" the initial call on
"Initialize" or "Adjust."

Fundamentally it seems *much* safer to require that
implementations recognize that constants of such
types are potentially updated through "general"
access values, than to somehow declare that the
preservation of such access values past an object's
initialization phase is erroneous and "programmer
beware."  Given that the Rosen trick as applied
to limited types has been a well-established technique
during Ada 95, it seems hopeless to outlaw it now.
Furthermore, given "privacy" concerns, an Ada 95
programmer might have taken advantage of it, and
then an Ada 2005 programmer might have taken
advantage of declaring a constant of such a limited
type without studying the private part of every
package and generic package that might be relevant
to know that the Rosen trick is in play.

As Ed points out, the more general loophole associated
with extended return has been closed, and I agree that
if it had not been closed, we would have a much bigger
problem on our hands.  But if you limit this to
immutably limited types and controlled types, the Rosen
trick seems like a reasonable engineering approach to
avoid having to introduce a separate writable component
in the heap to implement a particular abstraction that
has a well-defined notion of what it means to be
"partly constant."  For example, you can "Read" and
"Write" using a constant of a "File_Type" in Direct_IO,
but you can't "Open" or "Close" it.  Be that as it
may, we know that Read and Write advance the Index
associated with the File_Type, even though the File_Type
is an "in" parameter.  Clearly the Index must be
maintained in a part of a "constant" File_Type that
is updatable.  Must this necessarily be in the heap?

****************************************************************

From: Erhard Ploedereder
Sent: Saturday, February 16, 2008  9:46 AM

Ed, you are making me jump through hoops here. ... :-)

The following, without aliased in the extended return, and still compliant with
the revised 13.9.1(13) of AI-54/2, and still an access-to-variable to a
constant and still not a limited type.

More or less for the archive of AI-54-2/3 to deal with this case as
well in any final wording. Is this an issue for AI-53 as well?

with Ada.Finalization; use Ada.Finalization;
package ConstantsC2 is
   type T is private;
private
   type Selfptr is access all T;
   type Handle_Type (Gen : Selfptr) is
      limited null record;
   type SidePtr is access all Handle_Type;


   type T is new Controlled with
      record
         Z    :   Integer := 5;
         Comp :   sidePtr;
      end record;

   procedure Foo (X : in     T);
   procedure Adjust (X : in out T);

end ConstantsC2;
with Text_IO;
with System.Address_to_Access_Conversions;
package body ConstantsC2 is

   package P is new System.Address_To_Access_Conversions(T);

   procedure Foo (X : in     T) is
   begin
      X.Comp.Gen.Z := 8;
   end Foo;

   function Inplace return T is
   begin
      return X: T do
         X.Comp := new Handle_Type(selfPtr(P.To_Pointer((X'Address))));
      end return;
   end;
   procedure Adjust (X : in out T) is
   begin
     X.Comp := new Handle_Type(selfPtr(P.To_Pointer((X'Address))));
   end Adjust;

   X : constant T := Inplace;

begin
   Foo(X);
   Text_IO.Put_Line(Integer'Image(X.Z));
end ConstantsC2;

with ConstantsC2;
procedure TestconstantsC2 is
begin
   null;
end TestconstantsC2;

****************************************************************

From: Robert Dewar
Sent: Saturday, February 16, 2008  10:16 AM

> As Ed points out, the more general loophole associated
> with extended return has been closed, and I agree that
> if it had not been closed, we would have a much bigger
> problem on our hands.  But if you limit this to
> immutably limited types and controlled types, the Rosen
> trick seems like a reasonable engineering approach to
> avoid having to introduce a separate writable component
> in the heap to implement a particular abstraction that
> has a well-defined notion of what it means to be
> "partly constant."

Sounds reasonable to me, I assume you are referring to
the "Rosen technique" in the above? :-)

****************************************************************

From: Erhard Ploedereder
Sent: Saturday, February 16, 2008  11:18 AM

Let me summarize the points that I am trying to make with the examples...

Point 1:
Clearly, it is not just limited types but also non-limited controlled types 
that are subject to the problem that access-to-variables can be used to 
modify a constant. This is independent of AI-53.

Point 2:
AI-54-2/3 in its re-formulation of 13.9.1(13) is very general in nature.
So much so that already today I can squeeze through unintended holes.

First I squeezed past limitedness.  After all, "Rosen works only for
limited types". Wrong! (Ed, sorry for confusing the issue by also involving
in-place initialization in the example. I did not need the "aliased" for 
the access-to-variable generation by Adjust.)

Then I squeezed past the missing AI-53 "aliased" for the hypothetical
in-place initialization case for non-limited constants, which, however it is
achieved, will give me variable access to all constants such initialized.
And nobody has told me that such in-place initialization is forbidden.

It is a very fragile net that is woven by AI-54 to allow access-to-variable
on constants in some but not all cases.  
---------------------------------

So, to legitimize Ada95 Rosen for constants, at least try to not
generalize it beyond limited types.

I could live with a notion that limited constants are an obsolete feature of
the language, with the possibility that such constants aren't constants,
while the feature is still supported. 

But, if I have to give up on controlled constants and who-knows-whatelse
constants because the above creates generic contract problems, then I'd
rather see the Rosen Trick for constant limited objects to stay erroneous
(or become a bounded error as I proposed) than to see declared constants of 
various kinds become variable.

The Rosen trick for constant objects has been erroneous for 12 years now or
maybe even longer.  Why should we be willing to damage the concepts of
constants to change it into legitimate behavior?

****************************************************************

From: Tucker Taft
Sent: Saturday, February 16, 2008  11:27 AM

Could you answer the general question of whether
you think it is a legitimate engineering solution
to use the Rosen "technique" to avoid having to
use the heap.  Being an implementor of a highly
optimizing compiler, I certainly understand
your concern.  On the other hand declaring something
erroneous is the ultimate "penny in the fusebox"
solution to a situation like this.

****************************************************************

From: Erhard Ploedereder
Sent: Saturday, February 16, 2008  11:50 AM

> ... the Rosen trick seems like a reasonable engineering approach to
> avoid having to introduce a separate writable component
> in the heap to implement a particular abstraction that
> has a well-defined notion of what it means to be
> "partly constant."

But see, that is not how the Rosen trick is applied in 
almost all cases. It is applied to get around the constant
view that an IN parameter imposes, not around the constantness
of the object itself. 

From the client side a constant object of a limited type is
a bit of a tautology, isn't it? You cannot assign to a limited object
or assign to one of its components. So why would you declare
an object of this type constant? So that you cannot assign to it or
one of its components, because you don't trust limited to do the
job?

If you do consider limited to be an abstraction that says: "client shall not
change this object; changes are reserved to the server."  then a "constant"
declaration by the client is in some sense a violation of the contract,
since the client interferes with the ability of the server to do as needed,
and on the client side it is a useless restriction, since the "constant view
for the client" is already enforced by "limited".

Which is why I would rather see "constant" on limited objects be
the punished culprit than the perfectly legitimate and useful
"constant" on controlled objects or any other that we might still 
discover to be subject to access-to-variable semantics with what
is currently proposed.

And, yes, "there are billions and billions constant limited objects
out there". I believe it when I see it. Just as there were billions
and billions of delta constraints, who still live happily ever after in
Annex J land. A lesser punishment would indeed be to send only those
constant limited objects that have a Rosen flavor into the neighboring 
country of Bounded-Error land.   

****************************************************************

From: Robert Dewar
Sent: Saturday, February 16, 2008  12:38 PM

>> ... the Rosen trick seems like a reasonable engineering approach to
>> avoid having to introduce a separate writable component
>> in the heap to implement a particular abstraction that
>> has a well-defined notion of what it means to be
>> "partly constant."
> 
> But see, that is not how the Rosen trick is applied in 
> almost all cases. It is applied to get around the constant
> view that an IN parameter imposes, not around the constantness
> of the object itself. 

Well anything that helps us get past this extremely
annoying restriction in Ada is worthwhile (we have
quite a lot of uses of Unrestricted_Access to deal
with this case :-))

****************************************************************

From: Dan Eilers
Sent: Saturday, February 16, 2008  12:55 PM

> Could you answer the general question of whether
> you think it is a legitimate engineering solution
> to use the Rosen "technique" to avoid having to
> use the heap.

I don't consider the Rosen "technique" to be
"legitimate engineering".  It is at best a kludge,
involving unnecessary space and time overhead,
and reducing code readabilty.

It seems that Ada could avoid the need for such
kludges by providing syntax to indicate that a
field of an otherwise constant record is mutable.
This would elegantly solve the problem for File_Type,
and and also the similar problem for mutable generator
state in the random number packages.

****************************************************************

From: Erhard Ploedereder
Sent: Saturday, February 16, 2008  1:27 PM

> Could you answer the general question of whether
> you think it is a legitimate engineering solution
> to use the Rosen "technique" to avoid having to
> use the heap. 

Sure I can answer this. It is an o.k. engineering solution to get around the
limitation imposed by (limited) IN parameters, since indeed I may have 
modifiable views on the variable actual parameter. Do I want it for 
that to avoid using the heap? Given such IN parameters, sure, I want it. But
then, I already have it. Well defined, legal and all, ever since the Rosen
Trick was invented. I keep saying that this covers >90%, if not 99,99%
of the territory. (Don't worry, I'll come back to this.)

It is not an o.k. engineering solution to get around the limitation imposed
by constantness of an object. And I do not need that engineering solution,
since I do not have the problem in the first place, because I do not make
limited objects constant. What for would I do this? Ok, ok, others might.

Engineering solution or not for a problem, a sanctioned solution shall never
violate a specification. The latter is the very definition of an error,
diagnosed or not.

Where we differ is in how far we are willing to change the specification 
(of constants) to allow for the Rosen trick to be applied to objects whose
constantness has been specified at the point of creation.

If one argues that the user cannot/should not know whether portions of a
limited object can be changed, he ought not be allowed to call it a
constant.  Everything else would then already be in place for the 
engineering solution to avoid the heap. The constant view is already
enforced for his side of the fence by the limitedness.

The only thing that stands in the way is the upward-compatibility issue.
Therefore my view of going the Annex J or the Bounded-Error route, but not
mess with the notion of constant objects.

Your view seems to be that the Rosen Trick cannot be applied unless the 
language guarantees that it also works for constant objects, since there 
could be some future user who would be surprised if he could not make his
limited object constant. I have no sympathy for this future user. He should
not even consider this possibility. 

Yes, I realize that there is a fine point: constants cannot be IN OUT
parameters. But to say that the user ought be able to prevent IN OUT
changes of objects, while being forced to accept hidden changes to IN 
parameters, is a bit hair-splitting to me.
  
As we are discussing this, you see my position shifting gradually to 
also consider prohibiting constant limited objects altogether, probably 
along the Annex J route. It would avoid a tie-in to whether or not Rosen
was applied on the other side of the fence.
But then, we are considering AI-53 with all those billions and billions of
"aliased" extended returns already in place; maybe we can be more rigorous
about it and just plain forbid these constants :-)

****************************************************************

From: Edmond Schonberg
Sent: Saturday, February 16, 2008  4:35 PM

> Ed, you are making me jump through hoops here. ... :-)

I can only admire your agility, but if it takes two levels of  
indirection, an unchecked conversion, and an access discriminant on a  
non-limited type to make use of this language hole, it cannot be a  
very large one, and the solution should be equally modest. Declaring  
such access a bounded error seems appropriate.

> The following, without aliased in the extended return, and still  
> compliant with the revised 13.9.1(13) of AI-54/2, and still an
> access-to-variable to a constant and still not a limited type.

Yes, it's instructive that neither self-reference nor limitedness are  
needed.  With a bit of effort you might be able to do without  
controlled types  as well :-)!

****************************************************************

From: Erhard Ploedereder
Sent: Saturday, February 16, 2008  6:48 PM

> With a bit of effort you might be able to do without  controlled types 
>  as well :-)!

That is exactly what I am afraid of, i.e., interactions that aren't 
necessarily there today, but might be tomorrow. That is why I am saying 
that "access-to-variable is o.k. for constants, as long as they were 
obtained from a variable-view of the constant" is such an indirect way 
of trying to capture an intent to allow them for limited constants, that
dragons live there. Some of them are Controlled, as we now know.

****************************************************************

From: Tucker Taft
Sent: Saturday, February 16, 2008  9:43 PM

I'll admit to have pretty much lost the thread here.
If we look at the particular case of Direct_IO.File_Type,
someone made the decision that they wanted to have
the IN vs IN-OUT distinction for these types correspond
to allowing read/write vs. allowing open/close.
We all seem to have gotten used to that, and it
seems vaguely reasonable.  Of course if Ada had a whole
"capability-based" system, we could split hairs much
more finely.  But all we have is IN vs. IN-OUT, and
we allow the implementor of an abstraction to require
variables for some operations and allow constants
for others.

Once you accept that it is up to the abstraction designer
to make this distinction between operations that have
IN parameters and those that have IN-OUT parameters,
it seems that the notion of "constant" has to be interpreted
in that context as well.  That is, "constant" simply
means that you can only pass the object to operations
that take IN parameters.  It really doesn't guarantee
anything about whether all parts of the state are
immutable.

Hence, my conclusion is that "constant" should mean
nothing more than that which the language enforces,
namely that you can't use a name that statically denotes a constant
declaration to pass (explicitly) an object to an operation that
uses "IN OUT" mode.  Period.  End of story.  Interpreting
"constant" to mean anything more than that seems like
a recipe for the programmer and the compiler to have
divergent views of reality, which is never a good thing.
If a programmer only passes an object to operations that
take IN parameters, then several compilers encourage
the programmer to declare such an object a constant.
It would be weird if having made an effort to make
limited and nonlimited work more alike in Ada 2005,
we eliminate the ability to declare limited objects
constant when they are initialized upon declaration,
and thereafter only passed to operations that have
IN mode.

Declaring something erroneous only makes sense in a language
like Ada if we think the programmer has to stand on their
head and go out of their way to do something, and trying
to make the compiler survive all such craziness is too
difficult, and we can't figure out any way to make what
such a programmer is doing illegal.

Using the access discriminant of a component to point
at the enclosing object is documented as a reasonable
thing to do, and described in the Ada 95 rationale.
Similarly initializing an access component of
a controlled type to point to the object itself during
the Initialize routine seems quite reasonable as
well, for example to create the head of a circularly
linked list.  If I then declare a constant of a
type Circularly_Linked_List, initialized by calling
a function that returns a pre-built list, I might choose
to have some operations that logically preserve the contents
of the list that use IN mode, and some that add
or remove elements that use IN-OUT mode, but it might
not be unreasonable for the IN mode operations to
do some amount of modification to implement some kind
of move-to-front optimization to speed access.
Who knows?  If things can be done easily and naturally
in the language, it seems very unsafe to declare
them as erroneous.

I am happy to limit this explicitly to controlled
and immutably limited types, as those are the
two that provide variable, aliased views naturally.
Would that satisfy your concerns?  I don't see
any generic contract issue here, since the aliased
variable view is only provided in cases where you
have a full view on the type.

All of the other examples almost certainly involve
standing on one's head, and/or using Unchecked_Conversion
or Address_To_Access_Conversion.

FWIW I consider Address_To_Access_Conversion to be
Unchecked_Conversion on steroids -- I have forgotten
why we didn't call it "Unchecked_Address_To_Access_
Conversion" ... seems like a big mistake at the moment.
I am happy to load up the description of this generic
with all kinds of erroneousness caveats, and to
encourage all style-checking tools to treat it as at
least as bad as Unchecked_Conversion.

****************************************************************

From: Randy Brukardt
Sent: Saturday, February 16, 2008  11:03 PM

Erhard is seriously confused and writes:

> Let me summarize the points that I am trying to make with the examples...
>
> Point 1:
> Clearly, it is not just limited types but also non-limited controlled types
> that are subject to the problem that access-to-variables can be used to
> modify a constant. This is independent of AI-53.

AI-53 doesn't have anything to do with this at all - please don't muddy the
waters. Moreover, this is a capability available in Ada 95, and that has
been used there.

In particular, Claw uses Initialize to hang newly created objects on various
lists. Those lists all use access-to-variable types. Surely someone could
declare a Claw object as a constant! How could Claw prevent or detect it?

Your position is that such a program is erroneous, because it doesn't make
sense for someone to do that (declare an object a constant). That may be
true, but our philosophy with Claw was to make the interface as idiot-proof
as possible (that is, we do everything possible to avoid having the program
die without reason). Ada doesn't provide us any way to detect that a
constant was created, and allowing such things to be erroneous simply allows
a compiler to generate trash if the user does this. I know darn well where
that bug report is going to end up, and it isn't going to be the user nor
the compiler writer that has this pain.

> Point 2:
> AI-54-2/3 in its re-formulation of 13.9.1(13) is very general in nature.
> So much so that already today I can squeeze through unintended holes.
>
> First I squeezed past limitedness.  After all, "Rosen works only for
> limited types".

This has nothing to do with limitedness, nor really with the Rosen trick.
The Rosen trick is just one way it shows up. Indeed, this also appears
whenever a type has an active component (like a task) or potentially
whenever a composite type has a component of an access-to-variable type.

This later case has existed in programming languages since the pointer was
invented. I'm not sure why you think that something new is going on! If an
composite type has an access-to-variable component, it might very well
consider what is at the end of that pointer logically part of the object.
And in that case, any operation on the type can change the values in the
portion of the object, even if it is IN parameter, and even if the object is
declared constant. (Claw does this, too, BTW, in order to share data between
objects that represent the same window).

There is nothing different about this case and the one in question: part or
all of the (logical) object can be modified even if it is declared constant.
So why is that so bad?

...
> Then I squeezed past the missing AI-53 "aliased" for the hypothetical
> in-place initialization case for non-limited constants, which, however it is
> achieved, will give me variable access to all constants such initialized.
> And nobody has told me that such in-place initialization is forbidden.

Of course it is all composite objects that have an access component that can
have this happen. There is nothing new about that (see above). No
"squeezing" needed!!

What I don't understand is what you are trying to "save" here. You've talked
about optimizations and analysis tools, but your examples aren't convincing
simply because it has been trivial since the introduction of the pointer for
their to be constant composite objects that have mutable parts. Any tool or
optimizer that doesn't take that fact into account is seriously broken. The
only way to make such assumptions is to look at the details of the type
(that is, to break privacy), and even then, the presence of any access
component eliminates the possibility of the object from being "constant" in
the sense that a tool would want to use.


...
> ---------------------------------
>
> So, to legitimize Ada95 Rosen for constants, at least try to not
> generalize it beyond limited types.

That doesn't work, because of controlled initialization, which is an obvious
way to construct resilient abstractions.

If you're saying that a system like Claw is poorly engineered because a user
mistake [declaring an object constant] allows a compiler to generate utter
garbage and destroy the invariants of the interface (and by corollary that
I'm a poor engineer for choosing that design), I have a response for you,
but it is not fit for public consumption.

> I could live with a notion that limited constants are an obsolete feature of
> the language, with the possibility that such constants aren't constants,
> while the feature is still supported.

They can hardly be obsolete: we just added them in Ada 2005! We did that
because people wanted them. But I don't think that they cared particularly
if they meet some bizarre notion of composite constantness...

> But, if I have to give up on controlled constants and who-knows-whatelse
> constants because the above creates generic contract problems, then I'd
> rather see the Rosen Trick for constant limited objects to stay erroneous
> (or become a bounded error as I proposed) than to see declared constants of
> various kinds become variable.

There never were controlled constants in Ada; if you think otherwise you
were sadly misled. (Of course, a particular type can be truly constant if
there is no aliasing and no access types around, but not in general.)

> The Rosen trick for constant objects has been erroneous for 12 years now or
> maybe even longer.  Why should we be willing to damage the concepts of
> constants to change it into legitimate behavior?

There are no such "concepts" for composite objects in Ada or any other
programming language that has pointers. Only scalar objects can be truly
constant.

The erroneousness in this case was always a bug in the language. If the
language was not going to prevent (by raising an exception, since it can't
be statically checked) the creation of access-to-variable views, then it has
to allow them to work.

Erroneousness is always bad! It allows absolutely anything to happen. And if
we know how something should work, and there is no implementation problem
with having it work (and that is the case here), then why should we allow
anything to happen?

As Robert previously noted, there are two kinds of erroneousness: cases that
language-lawyers think are erroneous, but are used and generally will work;
and cases where there is a genuine problem. This is surely one of the former
(rather than latter) cases.

I could live with a bounded error (from the perspective of Claw) IF such an
error allowed either the raising of Program_Error or working as written
(that is, as an access-to-variable). Allowing the wrong value to be accessed
is as bad as erroneousness in this case.

But I suspect that that solution would be considered wildly incompatible, as
it would make almost all programs containing limited and controlled types
subject to bizarre (and non-portable) exceptions being raised for no obvious
reason. And it is a privacy breakage and maintenance hazard: whether or not
a user can declare a constant of some type depends on the details of the
type. And implementing the actual check would have a distributed overhead
(you'd need a constant bit with either objects or parameters of controlled
types so that the check could be made in user-defined
Initialize/Adjust/Finalize.) So I think in fact I cannot live with a bounded
error.

The only solution that I see would be to somehow include this in the
contract (that is, in the partial view). But that seems a very heavy-weight
solution to a light-weight problem -- and, again, it is incompatible with
lots of existing code.

****************************************************************

From: Erhard Ploedereder
Sent: Sunday, February 17, 2008  8:25 AM

Let's agree that we disagree. But for the sake of others, let's describe our
positions in simple ways. Here is my version.

I am trying to save the notion that objects declared to be constants are
indeed constants and that this asserted invariance really holds. It can be
broken only by clearly identified Unchecked programming practices, which
then are deemed erroneous. This is the way it has been since 1980 in this
language.  To appease Randy and his fear that was has worked in practice for
12+ years might suddenly stop working, I tried the Bounded Error route in
lieu of erroneousness, but I refuse to change the existing notion of a
constant object as a truly invariant object.


Tuck and Randy want to legitimizing changes to constant objects in
situations where the Rosen Trick or its variants was needed (mostly on IN
parameters). The Rosen Trick has been legal only for variable actuals of
these IN parameters, and erroneous for constant actuals. It is a useful
idiom to avoid heap usage for hidden modifiable state, where stack usage
suffices just as well. To legitimize changes to constant objects, the notion
of asserted invariance has to disappear from the language. 
Tuck's model changes the semantics of a constant object declaration to only
introduce a constant view of a variable object. There are no more constants
(in the usual sense of the word) in Ada.  In many cases presently, but
possibly changing over time as the language evolves, such a constant view
may still guarantee invariance of the underlying object. The predicate for
invariance becomes "the object declaration has the constant keyword and
nowhere has the user succeeded to "legitimately" gain an access-to-variable
view on the object or has not used such a view later to change the
object". The "legitimately" part is presently worded in AI-54 as "anything
goes via legal attribute_references of any kind as long as it is during
initialization or finalization", but we might still narrow this some.

Did I summarize correctly?

****************************************************************

From: Erhard Ploedereder
Sent: Sunday, February 17, 2008  8:42 AM

Ooops, I misrepresented:
> object". The "legitimately" part is presently worded in AI-54 as "anything
> goes via legal attribute_references of any kind as long as it is during
> initialization or finalization", but we might still narrow this some.

should read:

object". The "legitimately" part is presently worded in AI-54 as "anything
goes via legal attribute_references applied to a variable view of the object
(e.g., during initialization, finalization or access to the object via an
access-to-variable view)", but we might still narrow this some.

(I just realized that of course you can get additional access-to-variable
 views in the midst of the object's lifetime, as soon as you have one of 
 them.) 

****************************************************************

From: Tucker Taft
Sent: Sunday, February 17, 2008  9:35 AM

I would suggest altering the new phrase proposed
in AI-54 for 13.9.1(13) as follows:

    ... 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{n aliased} variable view
    of the object

This makes it clear that we can't use 'Address
to bypass the requirement for being aliased.
An implementation that doesn't want to do
further analysis therefore has to presume that all
immutably limited and controlled objects are modifiable,
as these are the types for which an aliased variable
view can exist even if the object is declared "constant."
Of course you already have to be careful about
controlled objects in Ada 95 since you need to
recognize that Initialize, Adjust, and Finalize can
be applied to constant controlled objects.

We could go further (though we could mark part of it
as redundant) to say:

    ... 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{n aliased} variable view
    of [the] {a controlled or immutably limited} object.

Would either of these rewordings at least partially
satisfy your concerns?

****************************************************************

From: Erhard Ploedereder
Sent: Sunday, February 17, 2008  10:35 AM

The second version (with the explicit mention of controlled and
immutably limited) does address my concern about the generality
of the previous version. It certainly bounds which constants
are not constants.

Is Controlled here an innocent bystander caught by accident or
does anybody really believe that Adjust should be allowed to
squirrel away access-to-variable onto a controlled non-limited 
object? (An honest question, not rethorical.)

If innocent bystander, you could reduce it to the limited case.

"Limited" doesn't even raise a contract issue, since generic matching on
"limited" is an "if and only if"-match, so the body knows about limitedness
of the actual. 
For Controlled, nothing is known about the actual from the formal, so this
might cause contract issues. I have not thought that one through.

I certainly can live with limited constants that are not constants. In the
end, I have to, due to upward compatibility issues. 

-------
I would have suggested something identical for an obsolesced 
concept of constant limited objects, by saying that they are
just like all other constants, except that they are treated
as variables under an access-to-variable view per 13-9-1(13),
and hence changes are well defined. Maybe I'll write it up, 
just for comparision.

****************************************************************

From: Tucker Taft
Sent: Sunday, February 17, 2008 12:15 PM

I don't think there is any contract model
issue, because for a non-controlled limited type, you
get the aliased variable view inside the
full type definition, and for a controlled
type, you get the aliased variable view inside
the Initialize and Adjust procedures (and Finalize
of course, though that is a bit late to do much
damage).

As far as controlled being a "bystander" here,
I don't really think so.  One of the reasons to
make a type controlled is so that internal pointers
can be kept up to date across assignment.
I think the circularly-linked list is
a reasonable example.  I've included an
Initialize and Adjust implementation below.
At any given time, there are two pointers that
provide a variable view of the header node,
even for a constant object.  Although I didn't
show it, it might be reasonable to retain some
statistics in the header about number of references,
total links followed to find desired element, etc.

Here is an example of declaring a constant:

       C : constant Circularly_Linked_List :=
          Build_List(X, Y, Z);

Sample implementation follows.

---------------------

  generic
     type Element_Type is private;
  package Circularly_Linked_Lists is
     type Circularly_Linked_List is private;

     procedure Append(
       CLL : in out Circularly_Linked_List;
       Elem : Element_Type);

     ...

  private

     type CLL_Ptr is access all Circularly_Linked_List'Class;

     type Circularly_Linked_List is
       new Ada.Finalization.Controlled with record
         Next, Prev : CLL_Ptr;
     end record;

     procedure Initialize(CLL : in out Circularly_Linked_List);
     procedure Adjust(CLL : in out Circularly_Linked_List);
     procedure Finalize(CLL : in out Circularly_Linked_List);

     type Circularly_Linked_Node is
       new Circularly_Linked_List with record
         Payload : Element_Type;
     end record;

    ...

     procedure Initialize(CLL : in out Circularly_Linked_List) is
     begin
         CLL.Next := CLL'Unchecked_Access;
         CLL.Prev := CLL'Unchecked_Access;
     end Initialize;


     procedure Append(
       CLL : in out Circularly_Linked_List;
       Elem : Element_Type) is
         -- Add to end of list
         Old_Last : constant CLL_Ptr := CLL.Prev;
     begin
         CLL.Prev := new Circularly_Linked_Node'(
           Ada.Finalization.Controlled with
           Next => Old_Last.Next,
           Prev => Old_Last,
           Payload => Elem);
         Old_Last.Next := CLL.Prev;
     end Append;

     procedure Adjust(CLL : in out Circularly_Linked_List) is
       -- Do a deep copy of the circularly-linked list
         Old_First : constant CLL_Ptr := CLL.Next;
         Old_Header : constant CLL_Ptr := Old_First.Prev;
         New_Header : constant CLL_Ptr := CLL'Unchecked_Access;
     begin
         if Old_First = Old_Header then
             -- List is empty
             CLL.Next := New_Header;
             CLL.Prev := New_Header;
         else
             -- Copy each node with a payload
           declare
             Old_Node : CLL_Ptr := Old_First;
             Prev_Node : CLL_Ptr := New_Header;
           begin
             while Old_Node /= Old_Header loop
               declare
                 -- Copy the old node, and point back to the
                 -- new previous node
                 New_Node : constant CLL_Ptr :=
                   new Circularly_Linked_Node'(
                     Ada.Finalization.Controlled with
                     Next => null, Prev => Prev_Node,
                     Payload =>
                       Circularly_Linked_Node(
                         Old_Node.all).Payload);
               begin
                 -- Link into the previous node
                 Prev_Node.Next := New_Node;
                 -- Advance the pointers through
                 -- the new and old list
                 Prev_Node := New_Node;
                 Old_Node := Old_Node.Next;
               end;
             end loop;
             -- Hook the last new node
             -- into the new header
             Prev_Node.Next := New_Header;
             New_Header.Prev := Prev_Node;
           end;
         end if;
     end Adjust;

****************************************************************

From: Robert I. Eachus
Sent: Sunday, February 17, 2008  2:32 PM

> Let's agree that we disagree. But for the sake of others, let's describe our
> positions in simple ways. Here is my version.

> I am trying to save the notion that objects declared to be constants are
> indeed constants and that this asserted invariance really holds.
  
`When I use a word,' Humpty Dumpty said, in rather a scornful tone, `it
means just what I choose it to mean -- neither more nor less.' 

`The question is,' said Alice, `whether you can make words mean so many
different things.' 

`The question is,' said Humpty Dumpty, `which is to be master -- that's all.'


     -- Lewis Carroll in Through the Looking Glass


This is one of the most quoted literary paragraphs in legal jurisprudence,
and with good reason.  Erhard wishes for the word constant to mean what
he wants it to mean, not what it has always meant in Ada.

What Erhard would apparently prefer is that declaring an object to be
constant should override the implementation provided as part of the
declaration of the type. In Ada 83, Ada 95, and Ada 2006, the effect
of being a constant means lots of things--but it has never meant what
Erhard wants.

Perhaps the best way to put it is this. The defined behavior of a type
is pervasive. If you change the definition of a type, the new behavior
affects all object of that type, wherever declared.  If that requires
recompiling the world?  So be it.

However, the effect of declaring an object of a type to be constant
is local to that object. A declaration cannot be rejected simply because
the object is declared to be a constant. The Ada dependency rules force
this behavior. So, we are either left with requiring all object
declarations to support Erhard's view of how constant object should
behave--whether or not there are ever any constant objects of the type--or
the constant view is entirely local, and declarations elsewhere, including
of Initialize and Adjust, can trump that constant view internally.

I don't know why we are even having this discussion, let alone why it
has gone on so long. 6.4.1(5) requires: "If the mode is in out or out,
the actual shall be a name that denotes a variable." Seems clear.
Yet, Initialize, Finalize, and Adjust all take an in out parameter.
We can either depend on magic hand-waving, or admit that these procedures
see a variable view of the object. Similarly operations on
Storage_Pools (13.11) and Suspension_Objects (D.10) require in out parameters.

Does this mean that you can't declare (potentially useless) constant
objects of all these types? No. It means that constantness belongs to
a view or a name, and affects only the viewer. It is not a property of
the underlying object or type. For example, when a function returns a
value, the value returned is often not constant within (the body of)
the function. What is returned is a constant view of an object.

****************************************************************

From: Jean-Pierre Rosen
Sent: Monday, February 18, 2008  5:43 AM

> [...], but I refuse to change the existing notion of a
> constant object as a truly invariant object.
 
Sorry, but that was not the case in Ada 83. A constant object could have 
an access component, and part of its state contained into a heap object 
that could be changed at will.

The only difference with the case at hand is that we have now pointers 
to the same structure in place of pointers into an external structure, 
but it does not make much of a difference as far as theory of 
constantness is concerned.

****************************************************************

From: Robert Dewar
Sent: Monday, February 18, 2008  4:08 PM

> The only difference with the case at hand is that we have now pointers 
> to the same structure in place of pointers into an external structure, 
> but it does not make much of a difference as far as theory of 
> constantness is concerned.

I disagree, there is a huge difference between a constant object that
may have pointers and one that can be modified.

After all, in the sense you are trying to extend things to:

   X : constant Integer := 5;

might not be constant because 5 could be the index into an array whose
element #5 could be changed. Constantness is not about the conceptual
value in this sense, it is about the value in the narrow Ada sense,
and in this sense Ada 83 definitely has constants be real constants.

****************************************************************

From: Tucker Taft
Sent: Monday, February 18, 2008  4:22 PM

I think Jean-Pierre is talking about private
types.  When a client of a private-type
abstraction declares an object "constant" they
are really only restricting themselves to
passing the object to operations that have IN
mode.  They are in no way ensuring that the
logical state of the object is unchanging.

****************************************************************

From: Robert Dewar
Sent: Monday, February 18, 2008  4:51 PM

Certainly that's true, and as my example points
out, this has nothing to do with access values per se!

****************************************************************

From: Randy Brukardt
Sent: Monday, February 18, 2008  6:06 PM

> The second version (with the explicit mention of controlled and
> immutably limited) does address my concern about the generality
> of the previous version. It certainly bounds which constants
> are not constants.

Right, and that is fine. I don't much care about non-limited non-controlled
types (it's unlikely that an ADT would be constructed as one of these
anyway).

> Is Controlled here an innocent bystander caught by accident or
> does anybody really believe that Adjust should be allowed to
> squirrel away access-to-variable onto a controlled non-limited
> object? (An honest question, not rhetorical.)

I think it is fundamental to the model of controlled types given by Ada.
Claw works this way, and Tucker gives a reasonable example that is similar.

What I'm objecting to is having an ADT becoming erroneous (or raising an
exception for no obvious reason) if the user sticks "constant" on an object
declaration. That's a hazard to the safe operation of the ADT, and similarly
it is a maintenance hazard for fixes to the ADT (if anyone anywhere has
declared a constant of the ADT type, reasonable maintenance could make that
usage erroneous). This is an especial problem because style guides and
compilers both have been recommending for years that objects be declared
constant if possible (that is, if there is no usage that would prevent that
declaration). It should not be the case that following the recommendation of
a style guide (or a compiler message) makes a program unstable!

In practice, I don't mind limiting the rule to covering just types that are
immutably limited or controlled. It seems reasonable enough that if you want
to build a bullet-proof ADT, you have to make the ADT type controlled (many
factors tend to push you in that direction anyway). It's just another case
where only tagged types work "right".

The only acceptable solutions from the ADT perspective is either to work
"right" or to be statically detected (presumably by adding it to the
contract). Tucker's latest proposed wording essentially does both -
describes what it means to do it "right" - and essentially adds it to the
contract (if it is visibly controlled, it has to work right).

Thus, if you can live with Tucker's proposed wording, that would be fine
with me as well.

...
> I certainly can live with limited constants that are not constants. In the
> end, I have to, due to upward compatibility issues.

In the general case, it doesn't even make sense for limited (true) constants
to exist, as they may contain a task. As an active component, it surely is
changing the state of the object as it runs. (I realize many runtimes make
the task objects indirect, so it reduces to the access-in-an-object case.
But it is still logically changing.)

We may have made a mistake allowing such constants in Ada, but we made that
mistake by popular demand (to make limited types work more like non-limited
ones). And it seems too late to say "No, we didn't really mean it." And
doing that wouldn't fix the issues with non-limited controlled types anyway,
so it doesn't seem a productive path to visit.

****************************************************************

From: Randy Brukardt
Sent: Monday, February 18, 2008  6:12 PM

...
> I think Jean-Pierre is talking about private
> types.  When a client of a private-type
> abstraction declares an object "constant" they
> are really only restricting themselves to
> passing the object to operations that have IN
> mode.

And preventing the object from being the target of an assignment statement,
if the type is non-limited.

> They are in no way ensuring that the
> logical state of the object is unchanging.

Right. These can be powerful reasons for making an object constant, having
nothing whatsoever to do with whether the logical state can be changed.

****************************************************************

From: Jean-Pierre Rosen
Sent: Tuesday, February 19, 2008  1:21 AM

> Constantness is not about the conceptual
> value in this sense, it is about the value in the narrow Ada sense,
> and in this sense Ada 83 definitely has constants be real constants.
 
I was specifically answering to Erhardt's view that "constants should be 
constants". Conceptually, and for private types. And although I have a 
lot of sympathy for this view, I was noting that it was already not true 
in Ada 83.

****************************************************************

From: Robert Dewar
Sent: Tuesday, February 19, 2008  2:10 PM

But as I point out, in your conceptual sense, it could NEVER be true,
so it is a bit meaningless to adopt this conceptual sense.

****************************************************************

From: Erhard Ploederder
Sent: Monday, November 24, 2008  3:54 PM

I had the homework to create a NOTE about immutable constants. 

Here goes: 
-----------------------------

Add after 3.3(25):

The value of a constant object cannot be changed after its initialization, unless
the object has a controlled part or a part that is limited at the point of its
declaration (see 7.5 and 7.6).

-----
A bit of rationale: 

I left out the finalization bit, since for the types in question, finalization
can only be trivial.

The terminology on "controlled" parallels the verbage of 7.6 (10/2). If it is
wrong here, it is likely to be wrong there, too. For limited, I needed to
account for constant objects whose limited part became non-limited for
crucial moments. 

My first version read:
The value of a constant object cannot be changed after its initialization,
unless the object has a controlled part or limited part (see 7.5 and 7.6).

This looked nice and simple, except for a "becomes unlimited"-situation.
Maybe, as a user note, it would suffice regardless.
 
My second version was:
The value of a constant object cannot be changed after its initialization, unless
the object has a controlled part or limited part at the point of its declaration
(see 7.5 and 7.6).

This causes a contract question on "controlled", which could hide behind "private". 

So, I ended up with the above, which is as good or bad as 7.6 (10/2) wrt the
"controlled behind private" argument.  

The text of this Note could also be used in lieu of the deleted
   [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.] if one wanted to. In that case,
it should continue: 
In all other cases, the value of an object can be changed. 

****************************************************************

From: Randy Brukardt
Sent: Monday, November 24, 2008  4:17 PM

> The terminology on "controlled" parallels the verbage of 7.6 (10/2). 
> If it is wrong here, it is likely to be wrong there, too. For limited, 
> I needed to account for constant objects whose limited part became 
> non-limited for crucial moments.

Any particular reason that you did not use "immutably limited" in this wording,
as is done in both parts of the new normative wording? This wording is actually
slightly broader than needed, since it seems to include a type which is limited
by having a limited component (not necessarily immutably limited).

We used to have a whole bunch of different ways of saying "immutably limited",
but supposedly we've changed them all to use the new term. "Immutably limited"
is (already) used in 7 subclauses (and the index) and roughly 15 occurrences
in the revised AARM. It's a term that should quickly become familiar -- so I
don't think there is any good reason to avoid it.

I suppose that there is some value to explaining the rules in different terms,
but then it is odd that you're leaning on the defined term for "controlled" and
not for "immutably limited".

If you're not going to worry about whether you include too much in the note, then
I think I actually prefer your first wording:

"The value of a constant object cannot be changed after its initialization, unless
the object has a controlled part or limited part (see 7.5 and 7.6)."

because this is still a true statement (there are some objects with limited parts
that cannot be changed after initialization, but there aren't any objects that can
be changed that are not covered by the "unless"). The only extra cases covered by
the "unless" that don't have to be covered involve using limited private types that
have full types that aren't limited. And writing code that assumes that a limited
private type is implemented by something non-limited (and thus gets covered by
this note) sounds pretty dubious to me -- it makes the usage depend on the actual
implementation of the private type.

So for actual use, the simpler version probably is a good enough rule of thumb to
remember.

****************************************************************

From: Bob Duff
Sent: Monday, November 24, 2008  4:33 PM

> "The value of a constant object cannot be changed after its 
> initialization, unless the object has a controlled part or limited part (see 7.5
> and 7.6)."

Seems to imply that if it has a "controlled part or limited part", it can be
changed willy-nilly.  And "controlled part or limited part" = "controlled or
limited part".

So how about:

"The value of a constant object cannot be changed after its initialization, except
in some cases where the object has a controlled or limited part (see 7.5 and 7.6)."

****************************************************************

From: Erhard Ploederder
Sent: Tuesday, November 25, 2008  8:25 PM

Randy asked, why I didn't use "immutably limited".

Mainly, because I used the Springer book rather than the AARM to leaf through
definitions. So, no technical reason. It merely hasn't sunk in as new terminology
with me and so I would not have felt comfortable. Reading the modified 13.9.1(13)
in the AI, I guess it would be ok to add the "immutably" to the text. 

The "part"-part came from someone's observation at the meeting that it sufficed
to have a subcomponent of the ilk to make the enclosing constant object mutable
(merely by the fact that the subcomponent could be altered).
That made sense to me.

Bob's observations were good ones, too. 

How about:

The value of a constant object cannot be changed after its initialization, except
in some cases where the object has a controlled or immutably limited part (see 7.5,
7.6 and 13.9.1).

****************************************************************


Questions? Ask the ACAA Technical Agent