!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; -- Implicit declaration of overriding primitive (as per AI05-0042): -- procedure Prim (S : in out Task_Type); procedure Other_Prim (Tsk : in out Task_Type); end Synch_Pkg; ... T : Synch_Pkg.Task_Type; ... T.Prim; -- (1) Ambiguous? (No.) T.Other_Prim; -- (2) Ambiguous? (Yes.) 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. ****************************************************************