!standard 4.7 (03) 03-11-25 AI95-00332/03 !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 and object renamings !summary Access attributes, character literals, and other constructs requiring a single expected type can be used as the operand of a qualified expression and can be renamed. !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 8.6(27) by: When a construct is one that requires that its expected type be a *single* type in a given class, the type of 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 expected type of the construct is then this type. 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 type_conversion. AARM Note: The part of the first sentence after the semicolon serves to define the "expected type" for constructs that don't have one (like qualified expressions and renames). Otherwise, such constructs wouldn't allow aggregates and 'Access. !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. Just changing the definition of qualified expression doesn't work, however. First, there are other such constructs for objects (object renames and selected components come to mind). Fixing every one of them seems like a pain. prohibitive. Second, just defining the expected type of a qualified expression 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 their primary purpise of eliminating ambiguity. !corrigendum 8.6(27) @drepl 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. 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. @dby When a construct is one that requires that its expected type be a @fa type in a given class, the type of 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 expected type of the construct is then this type. 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. !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. **************************************************************** From: Tucker Taft Sent: Sunday, November 16, 2003 8:31 AM I offered to come up with better wording to fix the problem that certain contexts do not specify an expected type. These contexts generally indicate that something "shall resolve" to a particular type, and in some cases allow a universal type that covers it. We avoided the "expected type" terminology to bypass the rules in paragraph 8.6(21-25) which are looser than we would like. However, this creates problems with the legality rule in 8.6(27) which seems to require that an expected type be provided by all contexts. This rule is (currently) relevant to null, character, and string literals, to allocators, and to '[Unchecked_]Acccess (any others?). Here is the current wording for 8.6(27): When the expected type for a construct is required to be a *single* 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. 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 type_conversion. The second sentence seems OK as is. The first (long ;-) sentence is the problem, as it uses the term "expected" three times, and at least two of them are problematic. Here is a possible alternative for this first sentence: When a construct is one that requires that its expected type be a *single* type in a given class, the type of 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. That seems to solve the problem in my view, in that it only mentions "expected type" as part of identifying the case we are talking about, but doesn't require that the context actually *provide* such an expected type. Note that I have dropped the trailing phrase "the type of the construct is then this single expected type," which seems unnecessary with this new wording. The second sentence (which should remain) rules out cases where any type in a class is expected, which might require overload resolution to deal with cases where there just happens to be only one such type in scope. I'll keep working if others don't like the above rewording, but it seems sufficient to me... **************************************************************** From: Tucker Taft Sent: Sunday, November 16, 2003 8:38 AM > ... > This rule is (currently) relevant to null, character, and string > literals, to allocators, and to '[Unchecked_]Acccess (any others?). I forgot aggregates. **************************************************************** From: Robert Dewar Sent: Sunday, November 16, 2003 8:47 AM too bad someone did not forget aggregates when designing the language in the first place :-) :-) **************************************************************** From: Robert I. Eachus Sent: Sunday, November 16, 2003 10:13 AM As I remember it from my compiler days, aggregates as parameters weren't too bad, it was aggregate assignment that was a blinding headache. I just mention it because we are running into exactly the same mess in the other thread. Sometimes the aggregate takes its constraint from the target, and sometimes from the aggregate itself, and the compiler front-end may have to do a lot of work before it knows which case it is dealing with. **************************************************************** From: Randy Brukardt Sent: Monday, November 24, 2003 8:46 PM Yes, I think this works. Thanks for the effort. BTW, in addition to qualified expressions, object renaming uses the "shall resolve to" wording. Prefix calls (AI-252 and 4.1.3) also do, but those are restricted to names, so they never trigger this rule. ****************************************************************