!standard 4.7 (03) 03-07-26 AI95-00332/02 !class binding interpretation 03-07-25 !status work item 03-07-25 !status received 03-03-17 !qualifier Omission !priority Low !difficulty Medium !subject Resolution of qualified expressions !summary Access attributes, character literals, and other constructs requiring a single expected type can be used as the operand of a qualified expression. !question Which of the following allocators is legal? procedure test47 is type T1 is tagged null record; type T1_Acc is access T1; type T1_Class_Acc is access T1'Class; procedure Proc (X : in T1; Y : in T1'Class) is P1 : T1_Acc; P2 : T1_Class_Acc; begin P1 := new T1' (Y); -- IS THIS LEGAL? P2 := new T1'Class' (X); -- IS THIS LEGAL? end Proc; begin null; end test47; The language of 4.7(3) says the operand "shall resolve to" be of the type determined by the subtype mark, as opposed to most of the other name resolution rules that talk about what the expected type is. This seems to mean that the operand (or more strictly, an acceptable interpretation of the operand) has to be of the same type determined by the subtype mark. This would seem to mean that both are illegal, because Y resolves to T1'Class instead of T1, and X resolves to T1 instead of T1'Class. Is that the correct interpretation? (Yes.) Another question regarding qualified expressions: type T1 is record ... end record; type Acc_1 is access all T1; type Acc_2 is access all T1; X : aliased T1; procedure Some_Proc (Param : in Acc_1); procedure Some_Proc (Param : in Acc_2); Some_Proc (Acc_1' (X'Access)); -- OK (Yes.) Some_Proc (Acc_1' (null)); -- OK (Yes.) Are these qualified expression legal? (Yes.) One possible reading would say that it isn't, because 3.10.2(2) says that the type of X'Access is determined by the expected type, and the Name Resolution Rules for a qualified expression don't specify what the expected type of the operand is (again, unlike the Name Resolution Rules for many other Ada constructs). So if there's no expected type, 3.10.2(2) doesn't know what type X'Access should have. The same reading holds for 4.2(2). !recommendation (See Wording.) !wording Replace 4.7(3) by: The expected type of the operand (the expression or aggregate) is the type determined by the subtype_mark. Furthermore, notwithstanding what this International Standard says elsewhere, the operand shall have the type determined by the subtype_mark, or a universal type that covers it. AARM Note: This means that the operand must have exactly the type of the subtype_mark (or a universal type). This is different most other contexts, which allow classwide types to match specific types. !discussion Clearly we want the Access attribute, null, character literals, and so on, to work in qualified expressions. The entire point of qualified expressions is to resolve ambiguity in expressions, and the purpose would be severely compromised if some types of expressions could not be used in them. However, the "expected type" of the operand of a qualified expression is not defined. In order for the resolution rules for the above cases to work, the expected type needs to be defined. These are just some of the cases where the expected type is used in other rules. On the other hand, just doing that would trigger the rules of 8.6(22-25). But we definitely do not want the operand of a qualified expression to be a classwide type if the qualifying type is a specific type. Moreover, a legality rule would make some qualified expressions ambiguous, which would make qualified expressions less useful for eliminating ambiguity. Thus we adopt a rule which defines the expected type of the operand, and then adds additional constraints on the type of the operand. !corrigendum 4.7(03) @drepl The @i (the @fa or @fa) shall resolve to be of the type determined by the @fa, or a universal type that covers it. @dby The expected type of the @i (the @fa or @fa) is the type determined by the @fa. Furthermore, notwithstanding what this International Standard says elsewhere, the operand shall have the type determined by the @fa, or a universal type that covers it. !ACATS test Existing ACATS tests test resolution of qualified expressions, including various kinds of literals. !appendix !topic Qualified expressions, meaning of "resolve to" !reference RM95 4.7(3), AARM95 4.8(4a), RM95 3.10.2(24) !from Adam Beneschan 03-17-03 !discussion Which of the following allocators is legal? procedure test47 is type T1 is tagged null record; type T1_Acc is access T1; type T1_Class_Acc is access T1'Class; procedure Proc (X : in T1; Y : in T1'Class) is P1 : T1_Acc; P2 : T1_Class_Acc; begin P1 := new T1' (Y); -- IS THIS LEGAL? P2 := new T1'Class' (X); -- IS THIS LEGAL? end Proc; begin null; end test47; I have been going back and forth on this question, and now I'm not sure what the answer is. The language of 4.7(3) says the operand "shall resolve to" be of the type determined by the subtype mark, as opposed to most of the other name resolution rules that talk about what the expected type is. This seems to mean that the operand (or more strictly, an acceptable interpretation of the operand) has to be of the same type determined by the subtype mark. This would seem to mean that both are illegal, because Y resolves to T1'Class instead of T1, and X resolves to T1 instead of T1'Class. Is that the correct interpretation? If not, why not? AARM 4.8(4a) says, Ramification: For example, ... new S'Class ... (with no initialization expression) is illegal, but ... new S'Class'(X) ... is legal, and takes its tag and constraints from the initial value X. (Note that the former case cannot have a constraint.) Although this paragraph doesn't say specifically what X is, the implication seems to be that X can be a value whose type is any type in S'Class, and that the allocator takes its tag from the initial value. In other words the implication is that something like the assignment to P2 in the above example should be legal, which contradicts the interpretation I gave above. Another question regarding qualified expressions: type T1 is record ... end record; type Acc_1 is access all record; type Acc_2 is access all record; X : aliased T1; procedure Some_Proc (Param : in Acc_1); procedure Some_Proc (Param : in Acc_2); Some_Proc (Acc_1' (X'Access)); Is this qualified expression legal? One possible reading would say that it isn't, because 3.10.2(24) says that the type of X'Access is determined by the expected type, and the Name Resolution Rules for a qualified expression don't specify what the expected type of the operand is (again, unlike the Name Resolution Rules for many other Ada constructs). So if there's no expected type, 3.10.2(24) doesn't know what type X'Access should have. Sorry if this all seems pedantic, but I'm genuinely confused here, and am wondering if some clarification in the RM (or AARM) is warranted. I appreciate any assistance anyone can give. **************************************************************** From: Randy Brukardt Sent: Monday, March 17, 2003 11:52 PM > ...The language of 4.7(3) says the operand > "shall resolve to" be of the type determined by the subtype mark, as > opposed to most of the other name resolution rules that talk about > what the expected type is. This seems to mean that the operand (or > more strictly, an acceptable interpretation of the operand) has to be > of the same type determined by the subtype mark. This would seem to > mean that both are illegal, because Y resolves to T1'Class instead of > T1, and X resolves to T1 instead of T1'Class. "Shall resolve to" is commonly used in the RM (I found 30 pages using it in the AARM - check the search page at http://www.adaic.com/standards/95aarm/html/AA-SRCH.html). I believe that 8.6(14) is intended to define what "shall resolve to" means, although that description seems weak to me - and the AARM notes are no help. However, I believe the intent is that it resolves exactly to the type (the normal rules about class-wide types don't apply here). Thus, your original examples are illegal. > Although this paragraph doesn't say specifically what X is, the > implication seems to be that X can be a value whose type is any type > in S'Class, and that the allocator takes its tag from the initial > value. In other words the implication is that something like the > assignment to P2 in the above example should be legal, which > contradicts the interpretation I gave above. No, X has to have type S'Class. But of course the actual type of the object X could be any type in S'Class. That's just normal class-wide programming. I don't see any implication of the type of X here. >... > Some_Proc (Acc_1' (X'Access)); > > Is this qualified expression legal? One possible reading would say > that it isn't, because 3.10.2(24) says that the type of X'Access is > determined by the expected type, and the Name Resolution Rules for a > qualified expression don't specify what the expected type of the > operand is (again, unlike the Name Resolution Rules for many other Ada > constructs). So if there's no expected type, 3.10.2(24) doesn't know > what type X'Access should have. That does appear to be a hole, although you're looking at the wrong paragraph: it's 3.10.2(2) that defines this. (Note that 3.10.2(2) is substantially changed by AI-235, but still has the expected type wording). So it does appear that some connection between expected type and "shall resolve to" is necessary. But perhaps someone else can explain the (invisible) connection. > Sorry if this all seems pedantic, but I'm genuinely confused here, and > am wondering if some clarification in the RM (or AARM) is warranted. > I appreciate any assistance anyone can give. Well, we do need to be pedantic from time-to-time. It's not clear to me that the wording adquately embodies the intent. It is clear that 4.7(3) couldn't use "expected type", because that would allow class-wide matching, and that is not desired for qualified expressions. But I don't see any way to connect "shall resolve to" (which doesn't seem to be talking about types) to "expected types". I hope that Bob or Tuck enlightens us as to how the wording actually matches the intent. :-) **************************************************************** From: Tucker Taft Sent: Tuesday, March 18, 2003 10:50 AM I think we were a bit fast and loose with the phrase "single expected type." A qualified expression definitely creates an "expectation" for a "single" type, but doesn't use the term "expected type" itself (for good reason, as Randy points out, that would kick in the class-wide matching rules). So 8.6(27) should probably be clarified to explicitly included a qualified expression as a construct that satisfies the requirement for a "single expected type." ... > I hope that Bob or Tuck enlightens us as to how the wording actually matches > the intent. :-) I don't know if I helped, but I gave it a try... **************************************************************** From: Christoph Grein Sent: Thursday, March 20, 2003 5:25 AM > Thus, your original examples are illegal. Just for information - hope someone from ACT listens, Gnat 3.16a: procedure test47 is type T1 is tagged null record; type T1_Acc is access T1; type T1_Class_Acc is access T1'Class; procedure Proc (X : in T1; Y : in T1'Class) is P1 : T1_Acc; P2 : T1_Class_Acc; begin P1 := new T1' (Y); -- IS THIS LEGAL? Gnat says yes. not OK P2 := new T1'Class' (X); -- IS THIS LEGAL? Gnat says no. OK -- I think the effect of the above illegal statements -- can be achieved like so: P1 := new T1'(t1 (Y)); P2 := new T1'Class'(t1'class (X)); end Proc; **************************************************************** From: Tucker Taft Sent: Thursday, March 20, 2003 10:13 AM For what it's worth, I have attached the listing produced by the AdaMagic front end for this example. It rejects both of the illegal allocators. --- Source file: qualified.ada Thu Mar 20 11:11:07 2003 1 procedure qualified is 2 type T1 is tagged null record; 3 4 type T1_Acc is access T1; 5 type T1_Class_Acc is access T1'Class; 6 7 procedure Proc (X : in T1; Y : in T1'Class) is 8 P1 : T1_Acc; 9 P2 : T1_Class_Acc; 10 begin 11 P1 := new T1' (Y); -- IS THIS LEGAL? Gnat says yes. not OK * *****Error: LRM:8.6(28) Expression has no possible interpretation as an ***** expression of the type T1, Continuing 12 P2 := new T1'Class' (X); -- IS THIS LEGAL? Gnat says no. OK * *****Error: LRM:8.6(28) Expression has no possible interpretation as an ***** expression of the type T1'Class, Continuing 13 -- I think the effect of the above illegal statements 14 -- can be achieved like so: 15 P1 := new T1'(t1 (Y)); 16 P2 := new T1'Class'(t1'class (X)); 17 end Proc; 18 19 begin 20 null; 21 end; **************************************************************** From: Randy Brukardt Sent: Friday, July 25, 2003 5:42 PM Janus/Ada also rejects both allocators. **************************************************************** From: Randy Brukardt Sent: Friday, July 25, 2003 7:13 PM I've been working on the big backlog of boring AIs. I wrote up this AI, but am not very happy with the wording. Perhaps someone has a better suggestion. Anyway, here is the relevant question from the AI. (There is another question, which is why I'm not appending the AI itself.) --- type T1 is record ... end record; type Acc_1 is access all record; type Acc_2 is access all record; X : aliased T1; procedure Some_Proc (Param : in Acc_1); procedure Some_Proc (Param : in Acc_2); Some_Proc (Acc_1' (X'Access)); -- OK (Yes.) Some_Proc (Acc_1' (null)); -- OK (Yes.) Are these qualified expression legal? (Yes.) One possible reading would say that it isn't, because 3.10.2(2) says that the type of X'Access is determined by the expected type, and the Name Resolution Rules for a qualified expression don't specify what the expected type of the operand is (again, unlike the Name Resolution Rules for many other Ada constructs). So if there's no expected type, 3.10.2(2) doesn't know what type X'Access should have. The same reading holds for 4.2(2). --- Clearly, we want these cases to work, so the only question is what the wording should be to fix the whole. Tucker suggested changing 8.6(27), and since I don't see any other uses of "expected type" for the results of expressions, I did that. Replace 8.6(27) by: When the expected type for a construct is required to be a @i type in a given class, the type expected for the construct shall be determinable solely from the context in which the construct appears, excluding the construct itself, but using the requirement that it be in the given class; the type of the construct is then this single expected type. In particular, when a single type is required, the operand of a @fa identifies a single type (namely, the type specifed by the @fa), and that type is the expected type of the operand. Furthermore, the context shall not be one that expects any type in some class that contains types of the given class; in particular, the construct shall not be the operand of a @fa. The sentence starting with "In particular" is new. I'm not very happy with this wording. We're defining expected type for the operands of qualified expressions only when a single type is needed. Otherwise, there is no expected type. This seems necessary because in other cases the rules of 8.6(22-25) would be triggered, and we definitely don't want them used for the operands of qualified expressions. An alternative would be to replace 4.7(3) by: The expected type of the @i (the @fa or @fa) is the type determined by the @fa. The operand shall have the type determined by the @fa, or a universal type that covers it. This is goofy, because we're giving the rule twice, with the second more restrictive that the first. But maybe it is better?? (Note that the second rule cannot be a legality rule without introducing ambiguity where there currently is none.) **************************************************************** From: Robert A Duff Sent: Friday, July 25, 2003 7:43 PM > The expected type of the @i (the @fa or @fa) > is the type determined by the @fa. The operand shall have the > type determined by the @fa, or a universal type that covers > it. > > This is goofy, because we're giving the rule twice, with the second more > restrictive that the first. But maybe it is better?? Seems better to me. Maybe the goofiness can be attenuated by starting the second sentence with "Furthermore, ". **************************************************************** From: Gary Dismukes Sent: Friday, July 25, 2003 8:02 PM > type T1 is record ... end record; > type Acc_1 is access all record; > type Acc_2 is access all record; (Randy, if that's text from the AI then be sure to correct the access types to say "all T1" rather than "all record".:) > An alternative would be to replace 4.7(3) by: > > The expected type of the @i (the @fa or @fa) > is the type determined by the @fa. The operand shall have the > type determined by the @fa, or a universal type that covers > it. > > This is goofy, because we're giving the rule twice, with the second more > restrictive that the first. But maybe it is better?? It seems preferable if the fix can be applied in 4.7(3). However, I'm unclear on how this avoids triggering the 8.6(22-25) expected type rules. It seems like you're just creating a contradiction between this new rule and the 8.6 rules, but maybe I'm missing a subtlety of the wording that avoids invoking the type resolution rules. **************************************************************** From: Randy Brukardt Sent: Friday, July 25, 2003 8:24 PM That's why I thought it was goofy. OTOH, Bob's suggestion of "Furthermore, " helps. We could even go so far as "Notwithstanding", but that seems like overkill: The expected type of the @i (the @fa or @fa) is the type determined by the @fa. Furthermore, notwithstanding what this International Standard says elsewhere, the operand shall have the type determined by the @fa, or a universal type that covers it. That does eliminate all ambiguity, though. Maybe that IS the solution; it's not as goofy as the first one. **************************************************************** ****************************************************************