Version 1.3 of ai05s/ai05-0265-1.txt

Unformatted version of ai05s/ai05-0265-1.txt version 1.3
Other versions for file ai05s/ai05-0265-1.txt

!standard A.18.2(97/2)          11-12-16 AI05-0265-1/02
!standard A.18.2(137/2)
!standard A.18.2(139/2)
!standard A.18.2(141/2)
!standard A.18.2(145/2)
!standard A.18.2(147/2)
!standard A.18.2(228/2)
!standard A.18.2(230/2)
!standard A.18.3(69/2)
!standard A.18.3(83/2)
!standard A.18.3(85/2)
!standard A.18.3(86/2)
!standard A.18.3(142/2)
!standard A.18.3(144/2)
!standard A.18.4(15/2)
!standard A.18.4(38/2)
!standard A.18.4(40/2)
!standard A.18.4(41/2)
!standard A.18.4(75/2)
!standard A.18.5(61/2)
!standard A.18.6(94/2)
!standard A.18.7(14/2)
!standard A.18.7(36/2)
!standard A.18.7(86/2)
!standard A.18.7(95/2)
!standard A.18.7(96/2)
!standard A.18.8(85/2)
!standard A.18.9(113/2)
!standard A.18.10(0)
!standard A.18.18(0)
!standard A.18.19(0)
!standard A.18.20(0)
!standard A.18.21(0)
!standard A.18.22(0)
!standard A.18.23(0)
!standard A.18.24(0)
!standard A.18.25(0)
!class binding interpretation 11-10-27
!status Amendment 2012 11-10-27
!status ARG Approved 8-0-1 11-12-11
!status work item 11-10-27
!status received 10-10-02
!priority Low
!difficulty Medium
!qualifier Omission
!subject The location of tampering checks should be specified
!summary
Tampering checks occur whenever an operation of a container is called that is defined to tamper with the container.
!question
Wording like A.18.2(147.7/3):
Program_Error is propagated if any operation tampers with the elements of Container while the object returned by Constant_Reference exists and has not been finalized.
does not say when the exception is raised or at what point. This should be clarified.
!wording
Add the following paragraph after A.18.2(97/2), A.18.3(69/2), A.18.4(15/2), A.18.7(14/2), A.18.10(88/3), A.18.18(34/3):
When tampering with cursors is prohibited for a particular <container-kind> object <M>, Program_Error is propagated by a call of any language-defined subprogram that is defined to tamper with the cursors of <M>. Similarly, when tampering with elements is prohibited for a particular <container-kind> object <M>, Program_Error is propagated by a call of any language-defined subprogram that is defined to tamper with the elements of <M> (or tamper with the cursors of <M>), leaving <M> unmodified.
<M> is a letter, appropriate for each container (M for maps, V for vectors, and so on).
Modify A.18.2(139/3), A.18.3(83/3), A.18.4(38/3), A.18.7(36/3), A.18.10(117/3):
[Program_Error is propagated if Process.all tampers]{Tampering} with the elements of the <container-kind> that contains the element designated by Position {is prohibited during the execution of the call on Process.all}.
Modify A.18.2(137/2), A.18.2(141/2), A.18.2(145/2), A.18.3(85/3), A.18.4(40/3), A.18.7(95/2), A.18.10(118/3), A.18.18(48/3), A.18.18(50/3):
[Program_Error is propagated if Process.all tampers]{Tampering} with the elements of Container {is prohibited during the execution of the call on Process.all}.
Modify A.18.10(152/3), A.18.10(211/3), A.18.10(215/3):
[Program_Error is propagated if Process.all tampers]{Tampering} with the cursors of the <container-kind> that contains the element designated by Position {is prohibited during the execution of a call on Process.all}.
Modify A.18.2(228/2), A.18.3(142/2), A.18.4(75/2), A.18.7(86/2), A.18.10(151/3):
[Program_Error is propagated if Process.all tampers]{Tampering} with the cursors of Container {is prohibited during the execution of a call on Process.all}.
Modify A.18.2(147.14/3), A.18.2(147.17/3), A.18.3(86.7/3), A.18.3(86.10/3), A.18.4(41.7/3), A.18.4(41.10/3), A.18.7(36.6/3), A.18.7(96.11/3), A.18.10(126/3), A.18.10(129/3), A.18.18(57/3), A.18.18(60/3):
[Program_Error is propagated if any operation tampers with the elements of Container]{Tampering with the elements of Container is prohibited} while the object returned by <function_name> exists and has not been finalized.
Modify A.18.2(230.2/3), A.18.2(230.4/3), A.18.3(144.2/3), A.18.3(144.4/3), A.18.5(61.2/3), A.18.6(94.2/3), A.18.8(85.2/3), A.18.9(113.2/3), A.18.10(155/3), A.18.10(157/3), A.18.10(217/3):
{Tampering with the cursors of Container is prohibited while the iterator object exists} [Program_Error is propagated if any operation] (in particular, {in} the sequence_of_statements of the loop_statement whose iterator_specification denotes this object) [tampers with the cursors of Container while the iterator object exists].
Replace A.18.19(10/3), A.18.20(14/3), A.18.21(15/3), A.18.22(12/3), A.18.23(15/3), A.18.24(12/3), A.18.25(14/3):
It is a bounded error to assign from a bounded <container-name> object while tampering with elements Redundant[or cursors] of that object is prohibited. Either Program_Error is raised by the assignment, execution proceeds with the target object prohibiting tampering with elements Redundant[or cursors], or execution proceeds normally.
Erroneous Execution
When a bounded <container-name> object <V> is finalized, if tampering with cursors is prohibited for <V> other than due to an assignment from another <container-name>, then execution is erroneous.
AARM Reason: This is a tampering event, but since the implementation is not allowed to use Ada.Finalization, it is not possible in a pure Ada implementation to detect this error. (There is no Finalize routine that will be called that could make the check.) Since the check probably cannot be made, the bad effects that could occur (such as an iterator going into an infinite loop or accessing a non-existent element) cannot be prevented and we have to allow anything. We do allow re-assigning an object that only prohibits tampering because it was copied from another object as that cannot cause any negative effects.
!discussion
Ada 2005 wording like A.18.2(137/2) - "Program_Error is propagated if Process.all tampers with the elements of Container." is even worse in this regard, since it seems to imply that Process.all (a user-written routine) does this check.
By changing the wording to effectively make tampering a container state, it is much simpler to explain who makes the check and when it is going to happen. Since this matches the intended implementation, it should make the model clearer and reduce implementation mistakes.
We added an erroneous execution case to bounded containers because it is impossible to detect a tampering event caused by an assignment or other finalization. For example:
for C in My_List.Iterator loop ... My_List := Your_List; -- !! ... end loop;
For unbounded container forms, the assignment statement is required to raise Program_Error as My_List prohibits tampering of cursors, and the finalization of the target of the assignment is a tampering event.
The same is true for the bounded container forms, except that this cannot be implemented in Standard Ada. We do not allow bounded containers to depend on Ada.Finalization, so there will not be a call to some Finalize routine when My_List is finalized. Thus, there is no way to make the check to raise Program_Error. As such, a typical implementation will fail to raise Program_Error here.
That is OK, as we've defined execution to be erroneous in this case. That's necessary as the surrounding iterator probably will malfunction after this assignment, generating cursors that don't point at elements, possibly causing a hardware trap for a bad address or overwriting some other object's memory, or even going into an infinite loop.
!corrigendum A.18.2(97/2)
Insert after the paragraph:
the new paragraphs:
When tampering with cursors is prohibited for a particular vector object V, Program_Error is propagated by a call of any language-defined subprogram that is defined to tamper with the cursors of V, leaving V unmodified. Similarly, when tampering with elements is prohibited for a particular vector object V, Program_Error is propagated by a call of any language-defined subprogram that is defined to tamper with the elements of V (or tamper with the cursors of V), leaving V unmodified.
!corrigendum A.18.2(137/2)
Replace the paragraph:
If Index is not in the range First_Index (Container) .. Last_Index (Container), then Constraint_Error is propagated. Otherwise, Query_Element calls Process.all with the element at position Index as the argument. Program_Error is propagated if Process.all tampers with the elements of Container. Any exception raised by Process.all is propagated.
by:
If Index is not in the range First_Index (Container) .. Last_Index (Container), then Constraint_Error is propagated. Otherwise, Query_Element calls Process.all with the element at position Index as the argument. Tampering with the elements of Container is prohibited during the execution of the call on Process.all. Any exception raised by Process.all is propagated.
!corrigendum A.18.2(139/2)
Replace the paragraph:
If Position equals No_Element, then Constraint_Error is propagated. Otherwise, Query_Element calls Process.all with the element designated by Position as the argument. Program_Error is propagated if Process.all tampers with the elements of Container. Any exception raised by Process.all is propagated.
by:
If Position equals No_Element, then Constraint_Error is propagated. Otherwise, Query_Element calls Process.all with the element designated by Position as the argument. Tampering with the elements of the vector that contains the element designated by Position is prohibited during the execution of the call on Process.all. Any exception raised by Process.all is propagated.
!corrigendum A.18.2(141/2)
Replace the paragraph:
If Index is not in the range First_Index (Container) .. Last_Index (Container), then Constraint_Error is propagated. Otherwise, Update_Element calls Process.all with the element at position Index as the argument. Program_Error is propagated if Process.all tampers with the elements of Container. Any exception raised by Process.all is propagated.
by:
If Index is not in the range First_Index (Container) .. Last_Index (Container), then Constraint_Error is propagated. Otherwise, Update_Element calls Process.all with the element at position Index as the argument. Tampering with the elements of Container is prohibited during the execution of the call on Process.all. Any exception raised by Process.all is propagated.
!corrigendum A.18.2(145/2)
Replace the paragraph:
If Position equals No_Element, then Constraint_Error is propagated; if Position does not designate an element in Container, then Program_Error is propagated. Otherwise, Update_Element calls Process.all with the element designated by Position as the argument. Program_Error is propagated if Process.all tampers with the elements of Container
. Any exception raised by Process.all is propagated.>
by:
If Position equals No_Element, then Constraint_Error is propagated; if Position does not designate an element in Container, then Program_Error is propagated. Otherwise, Update_Element calls Process.all with the element designated by Position as the argument. Tampering with the elements of Container is prohibited during the execution of the call on Process.all. Any exception raised by Process.all is propagated.
!corrigendum A.18.2(147/2)
Insert after the paragraph:
Force a conflict; the real text is found in the conflict file.
the new paragraph:
Nothing.
!corrigendum A.18.2(228/2)
Replace the paragraph:
Invokes Process.all with a cursor that designates each element in Container, in index order. Program_Error is propagated if Process.all tampers with the cursors of Container. Any exception raised by Process.all is propagated.
by:
Invokes Process.all with a cursor that designates each element in Container, in index order. Tampering with the cursors of Container is prohibited during the execution of a call on Process.all. Any exception raised by Process.all is propagated.
!corrigendum A.18.2(230/2)
Replace the paragraph:
Force a conflict; the real text is found in the conflict file.
by:
Nothing.
!corrigendum A.18.3(69/2)
Insert after the paragraph:
the new paragraph:
When tampering with cursors is prohibited for a particular list object L, Program_Error is propagated by a call of any language-defined subprogram that is defined to tamper with the cursors of L, leaving L unmodified. Similarly, when tampering with elements is prohibited for a particular list object L, Program_Error is propagated by a call of any language-defined subprogram that is defined to tamper with the elements of L (or tamper with the cursors of L), leaving L unmodified.
!corrigendum A.18.3(83/2)
Replace the paragraph:
If Position equals No_Element, then Constraint_Error is propagated. Otherwise, Query_Element calls Process.all with the element designated by Position as the argument. Program_Error is propagated if Process.all tampers with the elements of Container. Any exception raised by Process.all is propagated.
by:
If Position equals No_Element, then Constraint_Error is propagated. Otherwise, Query_Element calls Process.all with the element designated by Position as the argument. Tampering with the elements of the list that contains the element designated by Position is prohibited during the execution of the call on Process.all. Any exception raised by Process.all is propagated.
!corrigendum A.18.3(85/2)
Replace the paragraph:
If Position equals No_Element, then Constraint_Error is propagated; if Position does not designate an element in Container, then Program_Error is propagated. Otherwise Update_Element calls Process.all with the element designated by Position as the argument. Program_Error is propagated if Process.all tampers with the elements of Container. Any exception raised by Process.all is propagated.
by:
If Position equals No_Element, then Constraint_Error is propagated; if Position does not designate an element in Container, then Program_Error is propagated. Otherwise, Update_Element calls Process.all with the element designated by Position as the argument. Tampering with the elements of Container is prohibited during the execution of the call on Process.all. Any exception raised by Process.all is propagated.
!corrigendum A.18.3(86/2)
Insert after the paragraph:
Force a conflict; the real text is found in the conflict file.
the new paragraph:
Nothing.
!corrigendum A.18.3(142/2)
Replace the paragraph:
Iterate calls Process.all with a cursor that designates each node in Container, starting with the first node and moving the cursor as per the Next function. Program_Error is propagated if Process.all tampers with the cursors of Container. Any exception raised by Process.all is propagated.
by:
Iterate calls Process.all with a cursor that designates each node in Container, starting with the first node and moving the cursor as per the Next function. Tampering with the cursors of Container is prohibited during the execution of a call on Process.all. Any exception raised by Process.all is propagated.
!corrigendum A.18.3(144/2)
Replace the paragraph:
Force a conflict; the real text is found in the conflict file.
by:
Nothing.
!corrigendum A.18.4(15/2)
Insert after the paragraph:
the new paragraph:
When tampering with cursors is prohibited for a particular map object M, Program_Error is propagated by a call of any language-defined subprogram that is defined to tamper with the cursors of M, leaving M unmodified. Similarly, when tampering with elements is prohibited for a particular map object M, Program_Error is propagated by a call of any language-defined subprogram that is defined to tamper with the elements of M (or tamper with the cursors of M), leaving M unmodified.
!corrigendum A.18.4(38/2)
Replace the paragraph:
If Position equals No_Element, then Constraint_Error is propagated. Otherwise, Query_Element calls Process.all with the key and element from the node designated by Position as the arguments. Program_Error is propagated if Process.all tampers with the elements of Container. Any exception raised by Process.all is propagated.
by:
If Position equals No_Element, then Constraint_Error is propagated. Otherwise, Query_Element calls Process.all with the key and element from the node designated by Position as the arguments. Tampering with the elements of the map that contains the element designated by Position is prohibited during the execution of the call on Process.all. Any exception raised by Process.all is propagated.
!corrigendum A.18.4(40/2)
Replace the paragraph:
If Position equals No_Element, then Constraint_Error is propagated; if Position does not designate an element in Container, then Program_Error is propagated. Otherwise Update_Element calls Process.all with the key and element from the node designated by Position as the arguments. Program_Error is propagated if Process.all tampers with the elements of Container. Any exception raised by Process.all is propagated.
by:
If Position equals No_Element, then Constraint_Error is propagated; if Position does not designate an element in Container, then Program_Error is propagated. Otherwise, Update_Element calls Process.all with the key and element from the node designated by Position as the arguments. Tampering with the elements of Container is prohibited during the execution of the call on Process.all. Any exception raised by Process.all is propagated.
!corrigendum A.18.4(41/2)
Insert after the paragraph:
Force a conflict; the real text is found in the conflict file.
the new paragraph:
Nothing.
!corrigendum A.18.4(75/2)
Replace the paragraph:
Iterate calls Process.all with a cursor that designates each node in Container, starting with the first node and moving the cursor according to the successor relation. Program_Error is propagated if Process.all tampers with the cursors of Container. Any exception raised by Process.all is propagated.
by:
Iterate calls Process.all with a cursor that designates each node in Container, starting with the first node and moving the cursor according to the successor relation. Tampering with the cursors of Container is prohibited during the execution of a call on Process.all. Any exception raised by Process.all is propagated.
!corrigendum A.18.5(61/2)
Replace the paragraph:
Force a conflict; the real text is found in the conflict file.
by:
Nothing.
!corrigendum A.18.6(94/2)
Replace the paragraph:
Force a conflict; the real text is found in the conflict file.
by:
Nothing.
!corrigendum A.18.7(14/2)
Insert after the paragraph:
the new paragraph:
When tampering with cursors is prohibited for a particular set object S, Program_Error is propagated by a call of any language-defined subprogram that is defined to tamper with the cursors of S, leaving S unmodified. Similarly, when tampering with elements is prohibited for a particular set object S, Program_Error is propagated by a call of any language-defined subprogram that is defined to tamper with the elements of S (or tamper with the cursors of S), leaving S unmodified.
!corrigendum A.18.7(36/2)
Insert after the paragraph:
Force a conflict; the real text is found in the conflict file.
the new paragraph:
Nothing.
!corrigendum A.18.7(86/2)
Replace the paragraph:
Iterate calls Process.all with a cursor that designates each element in Container, starting with the first element and moving the cursor according to the successor relation. Program_Error is propagated if Process.all tampers with the cursors of Container. Any exception raised by Process.all is propagated.
by:
Iterate calls Process.all with a cursor that designates each element in Container, starting with the first element and moving the cursor according to the successor relation. Tampering with the cursors of Container is prohibited during the execution of a call on Process.all. Any exception raised by Process.all is propagated.
!corrigendum A.18.7(95/2)
Replace the paragraph:
If Position equals No_Element, then Constraint_Error is propagated; if Position does not designate an element in Container, then Program_Error is propagated. Otherwise, Update_Element_Preserving_Key uses Key to save the key value K of the element designated by Position. Update_Element_Preserving_Key then calls Process.all with that element as the argument. Program_Error is propagated if Process.all tampers with the elements of Container. Any exception raised by Process.all is propagated. After Process.all returns, Update_Element_Preserving_Key checks if K determines the same equivalence class as that for the new element; if not, the element is removed from the set and Program_Error is propagated.
by:
If Position equals No_Element, then Constraint_Error is propagated; if Position does not designate an element in Container, then Program_Error is propagated. Otherwise, Update_Element_Preserving_Key uses Key to save the key value K of the element designated by Position. Update_Element_Preserving_Key then calls Process.all with that element as the argument. Tampering with the elements of Container is prohibited during the execution of the call on Process.all. Any exception raised by Process.all is propagated. After Process.all returns, Update_Element_Preserving_Key checks if K determines the same equivalence class as that for the new element; if not, the element is removed from the set and Program_Error is propagated.
!corrigendum A.18.7(96/2)
Insert after the paragraph:
Force a conflict; the real text is found in the conflict file.
the new paragraph:
Nothing.
!corrigendum A.18.8(85/2)
Replace the paragraph:
Force a conflict; the real text is found in the conflict file.
by:
Nothing.
!corrigendum A.18.9(113/2)
Replace the paragraph:
Force a conflict; the real text is found in the conflict file.
by:
Nothing.
!corrigendum A.18.10(0)
Insert new clause:
Force a conflict; the real text is found in the conflict file.
!corrigendum A.18.18(0)
Insert new clause:
Force a conflict; the real text is found in the conflict file.
!corrigendum A.18.19(0)
Insert new clause:
[A placeholder to cause a conflict; the real wording is found in the conflict file.]
!corrigendum A.18.20(0)
Insert new clause:
[A placeholder to cause a conflict; the real wording is found in the conflict file.]
!corrigendum A.18.21(0)
Insert new clause:
[A placeholder to cause a conflict; the real wording is found in the conflict file.]
!corrigendum A.18.22(0)
Insert new clause:
[A placeholder to cause a conflict; the real wording is found in the conflict file.]
!corrigendum A.18.23(0)
Insert new clause:
[A placeholder to cause a conflict; the real wording is found in the conflict file.]
!corrigendum A.18.24(0)
Insert new clause:
[A placeholder to cause a conflict; the real wording is found in the conflict file.]
!corrigendum A.18.25(0)
Insert new clause:
[A placeholder to cause a conflict; the real wording is found in the conflict file.]
!ACATS Test
None needed.
!ASIS
No change needed.
!appendix

From: Randy Brukardt
Sent: Wednesday, October 12, 2011  9:17 PM

Erhard has the following in his review:

...
> 36.6.3 says as part of the semantics of function Constant_Reference:
> > Program_Error is propagated if any operation tampers with the
> > elements of Container while the object returned by
> > Constant_Reference exists and has not been finalized.
>
> Not good enough. It doesn't say when and where it is raised (upon
> tampering, after tampering upon use of the returned value, or by
> Current_Reference which has mystical powers to know the future?)

I'm in favor of the mystical powers. ;-)

> To fix, and I presume that is the intent, "if" should be replaced by
> "when".

I'm not completely convinced that is enough, but it does seem to be an
(small) improvement. I worry that "any operation" seems to require user
subprograms to make such a check, which is obvious nonsense.

It might be better to say

Program_Error is propagated [if]{by} any operation {of Container that} tampers
with the elements of Container while the object returned by Constant_Reference
exists and has not been finalized.

maybe it would be better to name the package in question, but we can't do that
for Maps and Sets (there are multiple packages involved). Perhaps

...operation {of a set package that} tampers

although then someone will bitch that formally it is an instance that we're
talking about:

...operation {of an instance of a set package that} tampers

But I'm not sure this wording captures the dynamism necessary.

> I did not pick up on this earlier, because in other contexts "if" and
> "when" can be semantically interchangeable. But, here and elsewhere,
> when the semantics of function F say:
> Constraint_Error is raised if the value of XYZ is null.
> Programm_Error is raised if ...
> then I really assume that it is F that raises the exception, not some
> other subprogram later on.
>
> "when" solves the issue somewhat. Putting the rule elsewhere entirely
> would be better. Maybe even "collect" all the cursor types to which
> this rule applies and describe the tampering exception for all of them
> together.

That's probably how the tampering checks will get implemented, but I don't see
how to do that in a way that makes sense.

> [somewhat similar comment for 86/2, but it is not so bad there]

That of course is existing wording, so in theory it is out of bounds. But it
seems to me to be *worse* there, as it only talks about Process.all, but really
the exception will be raised by some call to a set operation that is
(dynamically) inside of Process.all. It's never going to be raised by
Process.all (which is user-written, so that would be an impossible requirement).

There is a similar problem with 36/2 (Query_Element). And all of the iterators.

If we make the changes suggested above, then we ought to make similar changes to
all of these other places.

For Query_Element, we would have something like:

Program_Error is propagated by any operation of an instance of a set container
that is called (directly or indirectly) from Process.all and that tampers with
the elements of Container.

This is getting wordy (and widespread). Better suggestions are welcome.

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

From: Erhard Ploedereder
Sent: Thursday, October 13, 2011  1:12 PM

>> > To fix, and I presume that is the intent, "if" should be replaced
>> > by "when".
> I'm not completely convinced that is enough, but it does seem to be an
> (small) improvement. I worry that "any operation" seems to require
> user subprograms to make such a check, which is obvious nonsense.

Why would that be the case? How do I tamper inside a user program without using
a tampering operation of the container package?

> It might be better to say
>
> Program_Error is propagated [if]{by} any operation {of Container that}
> tampers with the elements

Fine by me. Or "any operation defined in this International Standard"?
or "in this Clause".

In any case, I'd rather get the "when" without this additional chance than no
change at all.

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

From: Randy Brukardt
Sent: Thursday, October 13, 2011  1:47 PM

> > I'm not completely convinced that is enough, but it does seem to be
> > an
> > (small) improvement. I worry that "any operation" seems to require
> > user subprograms to make such a check, which is obvious nonsense.
>
> Why would that be the case? How do I tamper inside a user program
> without using a tampering operation of the container package?

Because I'm applying the same sort of unfriendly reading of the text that you
are when you say "if" needs to be replaced by "when". If you say the exception
needs to be raised "when any operation tampers", and mean it to specify which
operation is raising the exception [which is my understanding of the complaint],
I could read that as saying that some user operation that tampers needs to raise
the exception - possibly even before the inner call that actually does the
tampering. It's the same vaguely twisted logic that you use when you make the
claim that you need to know who raises the exception (there's only one practical
possibility, after all).

> > It might be better to say
> >
> > Program_Error is propagated [if]{by} any operation {of Container
> > that} tampers with the elements
>
> Fine by me. Or "any operation defined in this International Standard"?
> or "in this Clause".
>
> In any case, I'd rather get the "when" without this additional chance
> than no change at all.

My problem with that is that it doesn't really fix anything in this case (the
wording still tells you nothing about which operation actually makes the check -
which is the important point, isn't it?). And if there is a real problem here
(which I can believe), the existing Ada 2005 wording is many times worse.
Consider:

"Program_Error is propagated if Process.all tampers with the elements of
Container."

which is the wording used by Query_Element.

Applying the same logic that you did to the new wording, this clearly seems to
say that Query_Element itself is raising the exception. But that would too late
to raise it (the damage to the parameter to Process.all occurs as soon as any
tampering happens, and we don't want any possiblity to access the parameter
after that happens), and it would be hard to implement as well.

The intent is that the call to some operation that would tamper raises the
exception, but this doesn't say this at all.

I don't know if we left this purposely vague for some reason, or if we just
botched the wording.

In any case, it seems to me that if your comment is right, there are very
serious problems with the wording of all of the tampering checks. But this is
not a critical problem, in that there is only one sensible implementation, so
fixing the wording is unlikely to have any effect on implementations (while it
might be confusing for users - but I don't think they could take any real
advantage of an unfriendly reading).

Because the wording isn't going to change implementations, there is no rush to
get it right. And your suggestion of overhauling the descriptions of the
tampering check to make the part about where it gets raised a global statement
seems like it might be the best plan -- so we're talking about a lot of
rewriting. That should not be done as an "editorial review", so I think it would
be best to defer this (including your original comment) to an upcoming BI.

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

From: Erhard Ploedereder
Sent: Friday, October 14, 2011  9:02 AM

> If you say the
> exception needs to be raised "when any operation tampers", and mean it
> to specify which operation is raising the exception [which is my
> understanding of the complaint]

That is NOT my complaint. My complaint is that when a subprogram description
says:

Constraint_Error is raised if ...
Mode_Error is raised if ...
Set_Error is raised if ...
Program_Error is raised if ...

then I immediately expect that all these exceptions are raised by that
subprogram if the "if..." is true, not by some other subprogram SOMETIMES LATER.
The proposal of using "when" at least raises the attention level a bit, the "if"
does not.

Admittedly, a much better solution would be to drop that statement altogether in
this place and add a general statement somewhere, that in the presence of
"active cursors" (is there a term for it?) all tampering operations on the
"cursed container" raise Program_Error.

But really, I don't want the best be an enemy of the better.

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

From: Randy Brukardt
Sent: Friday, October 14, 2011  3:43 PM

> > If you say the
> > exception needs to be raised "when any operation tampers", and mean
> > it to specify which operation is raising the exception [which is my
> > understanding of the complaint]
>
> That is NOT my complaint. My complaint is that when a subprogram
> description says:
>
> Constraint_Error is raised if ...
> Mode_Error is raised if ...
> Set_Error is raised if ...
> Program_Error is raised if ...
>
> then I immediately expect that all these exceptions are raised by that
> subprogram if the "if..." is true, not by some other subprogram
> SOMETIMES LATER. The proposal of using "when" at least raises the
> attention level a bit, the "if" does not.

OK, but this is almost the same thing -- in the former case the text is
implicitly stating which routine is raising the exception; in this case, we're
not saying at all (in this wording or in the other existing wording) which
routine raises the exception. And that is a bad idea on the face of it.

> Admittedly, a much better solution would be to drop that statement
> altogether in this place and add a general statement somewhere, that
> in the presence of "active cursors"
> (is there a term for it?) all tampering operations on the "cursed
> container" raise Program_Error.
>
> But really, I don't want the best be an enemy of the better.

My concern here is it's become pretty obvious to me that the complaint that I
thought you were making is a real problem here. It would take me a couple of
hours to make the "if" => "when" change in all of the places that are affected,
and I'd rather spend that time on a real fix. So let me outline a real fix, and
if you find it acceptable, I'll create an AI out of it and ballot it for
immediate inclusion. [Delaying the standard a couple of days is better than
having a problem that will generate an immediate NB comment or possibly worse.]

That is, I want to go for "best", because I don't believe in what you say is
"better". (It's "better", but not enough better for the effort.)

[Aside: To answer the inevitable Duff rule complaint, I would say that the new
situations make the rules even muddier than they were, and show that the old
wording was too vague. So let's fix it completely if we need to hack around with
the new wording anyway.]

============================

Add the following paragraph after the definition of "tampering with elements",
etc. (in each container):

If tampering with cursors is *prohibited* for a particular <container-kind>
object <M>, Program_Error is propagated by any language-defined subprogram that
is defined to tamper with the cursors of <M>. Similarly, if tampering with
elements is *prohibited* for a particular <container-kind> object <M>,
Program_Error is propagated by any language-defined subprogram that is defined
to tamper with the elements of <M>.

[Note: The letter here is appropriate for the container kind: M for maps, V for
vectors, etc.]

Then, replace each place that currently talks about Program_Error for a
tampering check with something that says tampering is prohibited for that
container. For instance, Query_Element currently says:

Program_Error is propagated if Process.all tampers with the elements of
Container.

Replace that with:

Tampering with the elements of Container is prohibited during the execution of
Process.all.

Similarly, the sentence that caused the complaint says:

Program_Error is propagated if any operation tampers with the elements of
Container while the object returned by Constant_Reference exists and has not
been finalized.

Replace that with:

Tampering with the elements of Container is prohibited while the object returned
by Constant_Reference exists and has not been finalized.

And the iterator wording:

Program_Error is propagated if any operation (in particular, the
sequence_of_statements of the loop_statement whose iterator_specification
denotes this object) tampers with the cursors of Container while the iterator
object exists.

Tampering with the elements of Container is prohibited while the iterator object
exists (in particular, during the execution of the sequence_of_statements of the
loop_statement whose iterator_specification denotes this object).

Is this better? (Has to be :-), it matches the intended implementation.) Any
suggestions for improvement?

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

Questions? Ask the ACAA Technical Agent