Version 1.2 of ai05s/ai05-0090-1.txt
!standard 4.1.3(8-9.2/2) 08-02-04 AI05-0090-1/01
!standard 9.1(9.2/3)
!standard 9.4(11.1/3)
!class binding interpretation 08-02-04
!status work item 08-02-04
!status received 08-02-04
!priority Medium
!difficulty Medium
!qualifier Omission
!subject Ambiguities with prefixed views of synchronized primitives
!summary
A selected_component whose selector_name can denote the (implicit) overriding
of an inherited primitive of a synchronized type as well as an entry or
protected subprogram of that type that implements the inherited primitive
is not ambiguous, and resolves to the entry (or protected subprogram).
!question
Consider the following example:
package Synch_Pkg is
type Synch_Interface is synchronized interface;
procedure Prim (S : in out Synch_Interface) is abstract;
task type Task_Type is new Synch_Interface with
entry Prim;
entry Other_Prim;
end Task_Type;
--
--
procedure Other_Prim (Tsk : in out Task_Type);
end Synch_Pkg;
...
T : Synch_Pkg.Task_Type;
...
T.Prim; --
T.Other_Prim; --
The call to Prim at (1) using prefixed notation appears to be ambiguous,
because the selector could denote either the entry Prim, or the implicitly
declared overriding of the primitive inherited from Synch_Interface (which
is defined to exist by AI05-0042). This is clearly not what is intended.
Also, there can be subprograms with prefixed views that are homographic
with an entry of the task type, such as Other_Prim at (1), but that means
that calls using prefixed notation are ambiguous, because the call could
be either to the subprogram or to the entry (by 4.1.3 paragraphs 8-9.2/2).
Are such calls intended to be ambiguous? (Yes.)
!recommendation
(See Summary.)
!wording
[Note: This AI has not been discussed yet, so it's probably premature to
draft any wording, but here's a suggestion of how this might be fixed.]
To address the issue of preventing the ambiguity between the implicit
overriding declared for an inherited interface operation and an entry
or protected subprogram that implements it, one possibility would be
to introduce some kind of preference rule, presumably in 4.1.3. Another
approach would be to say that one or the other declarations is hidden
from all visibility at the point of a selector_name (excluding the
expanded name case).
Here's possible wording based on the latter, the intent of which is
to make the implicitly declared overriding subprogram hidden in the
context of the selector of a selected name that has a prefix of the
synchronized type:
In 8.3, add an additional bullet after paragraph 20.1/2:
The declaration of an implicit subprogram that overrides a subprogram
inherited by a task or protected type from a synchronized interface and
implemented by an entry or protected subprogram (as defined 9.1(9.2/3)
and 9.4(11.1/3)) is hidden from all visibility at the point of a
selector_name in a selected_component whose prefix resolves to an
object or value of the type.
[Or perhaps the preference should really be the other way around, with
with the entry or protected subprogram being hidden from all visibility in
a prefixed call:
The declaration of an entry or protected subprogram that implements
a subprogram inherited from a progenitor type is hidden from all
visibility at the point of a selector_name in a selected_component
whose prefix resolves to an object or value of the parent task or
protected type.
]
!discussion
The ambiguity in the case of the call at (2), to a synchronized operation
declared within a task or protected type that is a homograph of the prefixed
view of an explicit subprogram seems unavoidable. We could try to define
some preference rule similar to that for components that conflict
with prefixed views, as is done in 4.1.3(9.2/2), to select the entry
or protected subprogram interpretation, but that seems like a bad idea.
For one thing, unlike a component, such operations are overloadable.
Giving preference to either the synchronized operation or the subprogram
with the homographic prefixed view could too easily result in confusion
as to which operation was being named. Another possibility would be
to try and make certain declarations illegal, but that isn't appealing
either, as it would introduce illegalities for no particularly good
reason (plus it wouldn't work for technical reasons). So it seems better
to leave the language as it is, with the potential for ambiguities, but
ones that can generally be avoided either by changing names, using normal
function call notation rather than a prefixed view for calls to the implicit
overriding subprogram, or by using named notation on calls to distinguish
which operation is wanted. Thus, the answer to this part of the question
is really just a confirmation.
The first part of the question (concerning the call at (1)) involves
a similar case, but one where we definitely want the call to resolve
to one of the two available interpretations, since otherwise prefixed
notation can't be used at all.
The situation is that of a subprogram inherited from a synchronized
interface that is implemented by an entry or protected subprogram.
By AI05-0042, such an inherited subprogram is defined to be overridden
by an implicit subprogram (see the last sentence of 9.1(9.2/3) and
9.4(11.1/3)). The problem is that a call to the implicitly declared
overriding subprogram using prefixed notation will be ambiguous, because
it could also be interpreted as a call to the entry or protected
subprogram that implements the inherited subprogram. In some cases
such a call could be disambiguated using named associations for the
parameters, but having to futz with parameter names to disambiguate
calls would only be an ugly workaround and an inconvenience for users.
Clearly we need a change to effectively give preference to one of the
two operations. The proposed fix is to prefer the interpretation of
the entry (or protected subprogram), and to consider the implicit
overriding operation effectively hidden at the point of a selector_name
in a prefixed call. It seems somewhat more natural to prefer the entry
or protected subprogram over the implicit overriding subprogram since
the former is explicit in the program text (though formulating the
rule the other way could also be considered). In terms of the rules,
this is implemented by making the implicit overriding subprogram
hidden from all visibility at the point of a selector_name in cases
that would otherwise be ambiguous.
--!corrigendum 4.1.3(8-9.2/2)
!ACATS Test
An ACATS C-Test should be written to check that the legal case in the
example actually works.
!appendix
From: Gary Dismukes
Sent: Monday, February 4, 2008 4:44 PM
This is the draft version of the AI assigned to me in Fairfax (not assigned
a number yet) [this is version /01 of the AI - ED],
which arose out of a question raised during the meeting.
There are actually two similar questions involving apparent ambiguities
that can occur with prefixed calls to operations of synchronized tagged
types considered here. One of these cases of ambiguities doesn't seem
to require any action, but the other one needs correction. The most
appropriate way to fix this can be discussed at the upcoming meeting
(assuming this makes it to the agenda), but in this draft I've suggested
one way that it could be fixed.
****************************************************************
From: Edmond Schonberg
Sent: Monday, February 4, 2008 5:08 PM
...
> procedure Prim (S : Synch_Interface) is abstract;
S should be an in-out parameter if it is to be implemented by an entry.
...
> The call to Prim at (1) using prefixed notation appears to be ambiguous,
> because the selector could denote either the entry Prim, or the implicitly
> declared overriding of the primitive inherited from Synch_Interface (which
> is defined to exist by AI05-0042). This is clearly not what is
> intended.
Agreed.
> [Or perhaps the preference should really be the other way around, with
> the implicit overriding subprogram being hidden from all visibility in
> a prefixed call:
>
> The declaration of an entry or protected subprogram that implements
> a subprogram inherited from a progenitor type is hidden from all
> visibility at the point of a selector_name in a selected_component
> whose prefix resolves to an object or value of the parent task or
> protected type.
But in that case the second declaration would be legal, because the
implicit subprogram would then be overridden by the explicit one
according to the usual rules, and there would be no ambiguity. So
the first choice is preferable (if we want (2) to remain ambiguous.
****************************************************************
From: Gary Dismukes
Sent: Monday, February 4, 2008 6:35 PM
...
> > procedure Prim (S : Synch_Interface) is abstract;
>
> S should be an in-out parameter if it is to be implemented by an entry.
You're right, thanks for catching. I missed going back and making that
correction despite having corrected my compilation test of the same code.
[Correction made in version /01 of the AI - ED.]
> > [Or perhaps the preference should really be the other way around, with
> > the implicit overriding subprogram being hidden from all visibility in
> > a prefixed call:
(Aargh, I just noticed that I failed to adjust the wording on the above
paragraph after swapping some of my text around. That one should read
"with the entry or protected subprogram being hidden...". That's what
I get for running out of time and not doing a final careful review of
what I'd written. At least the next paragraph reflected what I meant
in the above.) [Correction made in version /01 of the AI - ED.]
> > The declaration of an entry or protected subprogram that implements
> > a subprogram inherited from a progenitor type is hidden from all
> > visibility at the point of a selector_name in a selected_component
> > whose prefix resolves to an object or value of the parent task or
> > protected type.
>
> But in that case the second declaration would be legal, because the
(I assume you mean "the second call" above rather than "second declaration".)
> implicit subprogram would then be overridden by the explicit one
> according to the usual rules, and there would be no ambiguity. So
> the first choice is preferable (if we want (2) to remain ambiguous.
I think there are two confusions here. First, the operation
Other_Prim called at (2) isn't a case of overriding, as there's
no inherited operation by that name in my example. But second,
if it were an overriding, then there would be a violation of the
rules in 9.1(9.6/2-9.8/2), which disallow having both an overriding
primitive and an "implemented by" operation for an inherited subprogram.
So I don't think that the fix for (1) would have any effect on the
ambiguity of cases such as (2).
****************************************************************
From: Edmond Schonberg
Sent: Monday, February 4, 2008 10:27 PM
> I think there are two confusions here. First, the operation
> Other_Prim called at (2) isn't a case of overriding, as there's
> no inherited operation by that name in my example. But second,
> if it were an overriding, then there would be a violation of the
> rules in 9.1(9.6/2-9.8/2), which disallow having both an overriding
> primitive and an "implemented by" operation for an inherited
> subprogram.
> So I don't think that the fix for (1) would have any effect on the
> ambiguity of cases such as (2).
Right, I misread the example, Other_Prim is well-named, and this is
definitely (unambiguously?) ambiguous.
****************************************************************
From: Tucker Taft
Sent: Monday, February 4, 2008 8:21 PM
> ... Another possibility would be
> to try and make certain declarations illegal, but that isn't appealing
> either, as it would introduce illegalities for no particularly good
> reason (plus it wouldn't work for technical reasons).
Can you explain these "technical reasons"?
We make it illegal to have an entry or
protected subprogram that is homographic with the
prefixed view of an explicit overriding. Why can't we
do the same for an explicit non-overriding primitive?
> ...
> Clearly we need a change to effectively give preference to one of the
> two operations. The proposed fix is to prefer the interpretation of
> the entry (or protected subprogram), and to consider the implicit
> overriding operation effectively hidden at the point of a selector_name
> in a prefixed call. It seems somewhat more natural to prefer the entry
> or protected subprogram over the implicit overriding subprogram since
> the former is explicit in the program text (though formulating the
> rule the other way could also be considered).
I strongly prefer having the entry/protected subprogram
visible via prefixed notation. That is what you would
get in the absence of the interface, and it seems weird
that the formal parameter names, defaults, etc., would
suddenly change just because the task type now implements
an interface. So I agree with your current solution, and
would be opposed to the alternate you considered.
> ...In terms of the rules,
> this is implemented by making the implicit overriding subprogram
> hidden from all visibility at the point of a selector_name in cases
> that would otherwise be ambiguous.
Do we really need to use the term "hidden from all visibility" here?
I think all you need to do is have 4.1.3(9.2) include a rule
that disallows referring to a primitive subprogram that is implemented
by an entry or protected subprogram. Remember that 4.1.3(9.2)
is all considered "Name Resolution" so disallowing something is
effectively creating an overload resolution rule. Hiding from
"all visibility" seems like overkill, and is probably exactly
what we *don't* want to do, since we still want to be able to
refer to the implicitly declared primitive using "unprefixed"
subprogram call notation.
****************************************************************
Questions? Ask the ACAA Technical Agent