!standard 3.2.4(21/3) 20-09-03 AI12-0066-1/03 !standard 4.4(7/3) !standard 8.5.1(6) !standard A.10.8(8) !standard A.10.9(13) !class confirmation 13-05-17 !status received 13-03-27 !priority Low !difficulty Easy !qualifier Omission !subject If it ain't broke... !summary This AI serves as a holder for questions that are not answered (or answered incorrectly) by the RM, but for which no one doubts the intent. !question (1) What are the rules for a parenthesized expression? The syntax is defined in 4.4(7/3), but there aren't any resolution or dynamic semantics rules defined in 4.4 or anywhere else. (2) What is the meaning of the name of a component being used as a direct_name (that is, without a prefix)? There does not seem to be any rule that specifies that it is the current instance (although that has been assumed by all since Ada 83). (3) When Ada.Text_IO.Get reads a integer number without a Width parameter, what gets read if the input is "2#101010"? A.10.8(8) says "reads the longest possible sequence of characters matching the syntax of a numeric literal without a point." Read literally, that means reading has to stop after reading the "2", as the entire value does not match the syntax of a numeric literal. That requires effectively infinite lookahead. The ACATS requires reading the entire string. Is this intended? (No.) (4) Consider: with Text_IO; procedure Aatsor is -- anonymous access to subprogram object renaming procedure Foo (X, Y : Integer) is use Text_IO; begin Put_Line ("X =" & Integer'Image (X)); Put_Line ("Y =" & Integer'Image (Y)); end; Ref : access procedure (Aaa, Bbb : Integer := 111); Renamed_Ref : access procedure (Bbb, Aaa : Integer := 222) renames Ref; begin Ref := Foo'Access; Renamed_Ref.all (Aaa => 333); end; The correct answer, according to 8.5.1(6), is X = 333Y = 111 But this doesn't make sense for the corresponding generic case (a formal in out parameter), as how could the body know what the parameters and defaults of the actual are? Something is wrong here. (5) The predicate-static rules (3.2.4(15-22/3) don't really work for a boolean subtype. Specifically, the predicate-static rules only allow the current-instance to be used as one of the operands of a relational operator, the operand of a membership, or the selector of a case expression. That means that the following are illegal: subtype Fooey1 is Boolean with Static_Predicate => Fooey1; -- ERROR: subtype Fooey2 is Boolean with Static_Predicate => Fooey2 or Debug; -- ERROR: In both of these cases, the current instance is not in one of the places allowed for a predicate-static expression. Should this be fixed? (6) The wording of 12.2(2) isn't quite right. If the generic body is a child of a generic package, then its elaboration establishes that each corresponding declaration nested in an instance of the parent (see 10.1.1) can from then on be instantiated without failing the Elaboration_Check. Consider how this wording applies to the elaboration of the (one and only) generic body in this example: generic package G1 is end; generic package G1.G2 is end; generic package G1.G2.G3 is pragma Elaborate_Body end; package body G1.G2.G3 is end; with G1; package I1 is new G1; with I1, G1.G2; package I2 is new I1.G2; with I2, G1.G2.G3; package I3 is new I2.G3; I3 is instantiating I2.G3 after the body of G1.G2.G3 has been elaborated. We want the elaboration check to pass, but this does not follow from a strict reading of the wording. In this context, the phrase "the parent" obviously refers to G1.G2. There are no instances of G1.G2 anywhere in this example. There is an instance of I1.G2, but that's not the same thing. Should this be fixed? (7) 3.3(23/5) says that "At the place where a view of an object is defined, a nominal subtype is associated with the view." 3.3(11) says that the result of evaluated an aggregate is an object. So what is the nominal subtype of an aggregate? Is it constrained or unconstrained? !response For these questions, we believe that adding proper wording to the Standard would be much more likely to introduce bugs than to clarify anything. Most of these issues date to Ada 83, yet they've never been addressed. (1) There are some rules that say parenthesized expressions have no effect in specific cases (6.2(10/3) and 7.5(2.1/3) are examples of such rules). But there is no general rule that says how the expression of a parenthesized expression is resolved nor what the value of it is. While this ought to be fixed in an ideal world, no one doubts what a parenthesized expression means and adding the missing wording probably would introduce bugs and questions (what is the accessibility of a parenthesized expression? [Well, Ada 2005 answered that question by adding 3.10.2(16.1/2).]), and would have absolutely no effect on implementations. (2) For example: type Acc is access all Some_Type; protected Stack is procedure Push (Item : in Acc); function Pop return Acc; private Stack_Head : Acc := null; end Stack; protected body Stack is function Pop return Acc is Temp : Acc := Stack_Head; begin Stack_Head := Stack_Head.Next; -- Illegal. return Temp; end Pop; procedure Push (Item : in Acc) is begin Item.Next := Stack_Head; Stack_Head := Item; -- OK. end Push; end Stack; Everyone "knows" that the line marked Illegal isn't allowed because Stack_Head refers to the protected component of the current instance of Stack, and the current instance is a constant inside a protected function. But there is no rule in the Standard that says that Stack_Head refers to the component of the current instance. Similarly, in type Rec (D : Natural) is record S : String (1 .. D); -- D here is that of the current instance. end record; we ought to know that D refers to the discriminant of the current instance. Of course, everyone "knows" this is the meaning, so adding explicit wording simply would more likely get this wrong and it wouldn't have any effect on implementations. (3) A friendly reading of the wording is that characters are read so long as the string read could be legal (if incomplete) syntax of a numeric literal. This matches the behavior of the ACATS (and ACVC before it); it has always required reading the entire value of "2#101010". Since this wording has existed since Ada 83, and the strict reading in the question requires nonsense (implementing the effect of infinite lookahead would be expensive and would have undesirable effects on interactive reading), we believe that there is no real issue with the wording. Fixing it just would just make the wording more complex and introduce more opportunities for problems. A.10.9(13) raises similar issues for real literals. (4) The problematic generic case is: declare generic Formal_Obj : in out access procedure (Aaa, Bbb : Integer := 111); procedure G; procedure G is begin Formal_Obj.all (Aaa => 333); end; Actual_Obj : access procedure (Bbb, Aaa : Integer := 222); procedure Iii is new G (Formal_Obj => Actual_Obj); procedure P (X, Y : Integer) is use Text_Io; begin Put_Line ("X =" & X'img); Put_Line ("Y =" & Y'img); end; begin Actual_Obj := P'access; Iii; end; We'd destroy the generic contract model if the body of the generic had to somehow know the parameter names and defaults of the actual. (That would be especially problematic if the actual had different names for the parameters.) So, we need to either (A) require full conformance when renaming or instantiating objects with access-to-subprogram types, or (B) adopt a rule like 8.5.4(7) for object renamings and formal in out parameters. (A) is easy but potentially incompatible; (B) is likely to be a significant amount of work. But the problematic case is rarely likely to happen in practice (generic formal in out parameters are rarely used; anonymous access-to-subprogram types are rarely used outside of parameters, that means that using them together is rare squared). Indeed, this is so unlikely that we don't think it is worth fixing; the disruption to compilers outweighs any likely benefit to users. (5) The simple fix of just adding a bullet "the current instance" doesn't work because it would allow the current instance on the both sides of operators, which is not intended or desired. So a correct fix is relatively expensive. Moreover, there is an easy workaround to this problem: add "= True" to the expression: subtype Fooey1 is Boolean with Static_Predicate => Fooey1 = True; -- OK. subtype Fooey2 is Boolean with Static_Predicate => (Fooey2 = True) or Debug; -- OK. One also can easily write a range for any possible subtype of Boolean; it's never necessary to use a static predicate in the way that it might for an enumeration type with more than 2 literals. Finally, a constrained subtype of a boolean type is essentially a pathology. Such a subtype is either the same as Boolean without the constraint, or is a subtype with zero or one values - something that is not going to be useful in conditional expressions or statements. (Such a subtype is essentially equivalent to a Boolean constant.) Since this is a relatively useless construct, and the wording needed is relatively complicated and only useful for this construct, we choose not to fix this. (6) Fixing this probably would require a term (as the definition is recursive). Something like the following: The "ultimate corresponding generic unit" of a generic unit G is defined to be If G is declared in an instance of another generic unit G2, then the ultimate corresponding generic unit of G2.G; otherwise G. Then the present wording could be fixed to use this new term: If the generic body is a child of a generic package (see 10.1.1), then its elaboration establishes that any generic unit whose ultimate corresponding generic unit is that child unit can from then on be instantiated without failing the Elaboration_Check. However, this isn't quite right, as it wouldn't cope properly with generic package G1 is package Nested_Nongeneric is generic package G2 is end; end; end; package I1 is new G2; package I2 is new I1.Nested_Nongeneric.G2; where the name G1.G2 doesn't make sense. This is complicated enough, and the likelyhood that anyone would get the wrong answer is low enough, that we don't attempt to fix it. (7) 4.3 does not define the nominal subtype of an aggregate. There are no known rules that depend on the nominal subtype of an aggregate. There could be in a future version of the Standard, and those could decide whether the nominal subtype should be loose (unconstrained) or tighter (constrained). For instance, if we added the capability to write case statements on (some) records, the nominal subtype would matter to case completeness checking. In such a case, a tighter subtype would be preferred. !appendix From: Randy Brukardt Sent: Wednesday, March 27, 2013 11:22 PM Here's a fine Adam-style question for you guys. We all "know" that you can't modify a protected component inside a protected function. For instance: type Acc is access all Some_Type; protected Stack is procedure Push (Item : in Acc); function Pop return Acc; private Stack_Head : Acc := null; end Stack; protected body Stack is function Pop return Acc is Temp : Acc := Stack_Head; begin Stack_Head := Stack_Head.Next; -- Illegal. return Temp; end Pop; procedure Push (Item : in Acc) is begin Item.Next := Stack_Head; Stack_Head := Item; -- OK. end Push; end Stack; Why is this so? 3.3(21.2/3) says that the current instance of a protected type is a constant within a protected function. 9.5.1(2) (which supposedly is "redundant"), repeats that and parenthetically says that implies that components cannot be updated. So far so good. All we have to prove is that the current instance is somehow involved with writing "Stack_Head" in the example above. But I can't find anything like that. Component_Definitions are defined in 3.8, and there are various rules which allow them to be used as direct_names. But there doesn't seem to be any rule that says "when a name that denotes a component_declaration or discriminant_declaration is used as a direct_name (without a prefix), the component or discriminant is that of the current instance of the type (including within a task or protected body)." There's no such rule in 3.8, 4.1, 4.1.3, 8.2, 8.3, or 8.6. So where the heck is it? I find it hard to believe that there isn't any definition of this in the RM; it's been the rule since the beginning of time. Note that this also is necessary to define the meaning of the use of discriminants directly within type declarations (although there is no legality component to that as a discriminant is always a constant): type Rec (D : Natural) is record S : String (1 .. D); -- D here is that of the current instance. end record; **************************************************************** From: Steve Baird Sent: Thursday, March 28, 2013 2:38 PM > All we have to prove is that the current instance is somehow involved > with writing "Stack_Head" in the example above. I think you are right that the rule you are looking for is missing, and that it would have been good if it had been stated explicitly. At this point, however, I'd say that at most an AARM note is needed (and the need for that is debatable). As far as I know, we still don't have a rule defining the value of a parenthesized expression (at least in the case where the associated object of the expression is undefined). I think the issue you raise falls in the same "we would have fixed it if we had noticed it earlier, but now we give more weight to the if-it-ain't-broke rule" category. **************************************************************** From: Tucker Taft Sent: Thursday, March 28, 2013 3:14 PM ... > I think you are right that the rule you are looking for is missing, > and that it would have been good if it had been stated explicitly. ... I agree, it seems to be missing. There are some places where we come close to saying something about it, but don't quite do so. **************************************************************** From: Randy Brukardt Sent: Thursday, March 28, 2013 4:24 PM Thanks guys, it's good to know that I'm not nuts. Hopefully no one will be disputing ACATS tests on the basis that this isn't defined. I think I'll write up an AI with these two issues with the intent that we'll vote it no action ultimately (on the basis that a fix would be more likely to introduce bugs than clarify the semantics for a reader); that way, the issues will be on-the-record somewhere in case others are searching for the information. **************************************************************** From: Robert Dewar Sent: Tuesday, December 17, 2013 8:12 PM [Part of a message in an adminstrative ARG thread.] ... > As I said, it's not just obscurity: (1) Some things are untestable in > the context of the ACATS (like treatment of volatile objects), but are > important nevertheless. (2) Some things are just wording > clarifications for which no new test ought to be needed. We could of > course forget fixing wording when it is unclear (Bob has advocated > this), but I think that leaves us with a iffy foundation where there > is too much assumed knowledge. I don't think it is a good idea to have > the test suite (or worse, "common sense") substitute for Standard language. The test suite always substitutes for the Standard language. In some cases the language is defined by the test suite, rather than the RM, e.g. I think we never fixed the Text_IO problem (that requires reading just the 2 if a line contains 2#01010101010101010 [no closing #), but the ACATS test (and hence all compilers), read the whole thing, and raise data error. The unlimited lookahead required by the RM is nonsense. Or historically in the Ada 83 standard, subtype R is integer 1 .. dynamic-value; was clearly illegal from the RM, but required by common sense and the test suite. Yes, it got fixed in the RM, the pragmatic value of fixing it, precisely zero, that fix never had any impact on any compiler. **************************************************************** From: Randy Brukardt Sent: Tuesday, December 17, 2013 8:47 PM I believe that we've fixed as many of those cases that we know about. I don't doubt that some are left, but there really shouldn't be any - it been quite a while since one has turned up. I just looked up the wording in the RM for the above example, and I don't believe that it requires infinite lookahead. The Ada 95 wording says that Data_Error is raised if the "sequence finally input is not a lexical element". It's open to interpretation, but I think that means you read first and interpret later. Anyway, that's not particularly important. (My recollection about the above is that it was the ACATS, not the RM, that was requiring unjustifiable lookahead, but it was so long ago that I could very well be wrong). **************************************************************** From: Robert Dewar Sent: Wednesday, December 18, 2013 4:47 AM Your recollection is wrong, somewhere the RM used to say that the longest possible valid sequence of characters constituting an integer literal was read, e.g. if you have 123ABC, read just the 123. I am surprised if we ever fixed this, the quote above is irrelevant, since the issue is what sequence is finally input, there must be something else in the RM defining this! Otherwise 123ABC might raise data error. The ACVC test always required diagnosing a misssing # as per my example. (not relevant to this thread strictly, but interesting history) **************************************************************** From: Randy Brukardt Sent: Wednesday, December 18, 2013 5:38 PM > The ACVC test always required diagnosing a misssing # as per my > example. Your recollection of the rules is correct, in that A.10.8(8) has the words you remember. > (not relevant to this thread strictly, but interesting history) I'm not sure I agree that those words would cause the problem that you describe, since the # is part of the syntax of a numeric literal, so I would expect that 2#10101 would all be read. Perhaps the example you are thinking of is slightly different. Anyway, as you say, it's not relevant to this discussion. Plus I think that I was wrong in denying it in the first place. I'm now keeping a list of wording problems that we're not planning to fix (because the potential harm is greater than the value) [AI12-0066-1, "If it ain't broke..."] Obviously those are effectively defined by the ACATS because those features (parenthesized expressions and direct use of components in the current instance) have no wording whatsoever in the RM defining them. I'm keeping track of such things so that we have a list of such things for any future editor that wants to clean them up (and hopefully to prevent future questions on the topics, as they'll now be discoverable when searching the AIs). **************************************************************** From: Robert Dewar Sent: Wednesday, December 18, 2013 6:01 PM > I'm not sure I agree that those words would cause the problem that you > describe, since the # is part of the syntax of a numeric literal, so I > would expect that 2#10101 would all be read. Perhaps the example you > are thinking of is slightly different. But that's not what the words say, they say "then reads the longest possible sequence of characters matching the syntax of a numeric literal without a point" and 2#10101 does not match the syntax of a numeric literal! So the RM requires reading the 2 and then stopping (requiring arbitrary look ahead). **************************************************************** From: Randy Brukardt Sent: Wednesday, December 18, 2013 6:36 PM Yes, an unfriendly reading of the words could lead to such an interpretation. But of course such a reading clearly violates the Dewar rule (unlimited lookahead is clear nonsense), so I'd argue that the ACATS is just following what the RM actually means. That of course brings up the question of whether or not the RM ought to be changed whenever we have to invoke the Dewar rule. I think we agree that's not always necessary. Still, I suppose I should put this on the list of things in AI12-0066-1 that we're not going to fix as insufficiently broken. Ideally, we'd at least have any such known issues in the system, so that we don't have to argue about whether they exist. :-) **************************************************************** From: Robert Dewar Sent: Thursday, December 19, 2013 7:31 AM > Yes, an unfriendly reading of the words could lead to such an > interpretation. But of course such a reading clearly violates the > Dewar rule (unlimited lookahead is clear nonsense) Well it's easy enough to implement unlimited look ahead, just not a very good idea all things considered. remember it can't go beyond a line mark, and reading in line by line is perfectly sensible IMO. Furthermore, I can't imagine what a "friendly" reading might be, and it is not obvious to me how you write the substitute text. We obviously have to be able to read one character ahead, to deal with 123.4E which might be 123.4E2 OK 123.4EA Error? Stop at the E? To me this is actually something that should have been fixed probably at this stage, since it is presumably well defined by all implementations, not so important. **************************************************************** From: Tucker Taft Sent: Thursday, December 19, 2013 9:12 AM My interpretation is that you keep reading as long as it *might* be a numeric literal, and if you bump into a syntax error, then you raise an exception. You never need to backtrack. This is what AdaMagic and all its spin-offs implemented, including Patriot Ada, SHARKAda, ObjectAda, and AdaMulti. I believe this is what our Ada 83 compiler (the AIE) implemented as well. I agree that the reference manual wording is ambiguous. **************************************************************** From: Randy Brukardt Sent: Thursday, December 19, 2013 7:08 PM Gee, I thought I was done with this. :-) Robert Dewar writes: > > Yes, an unfriendly reading of the words could lead to such an > > interpretation. But of course such a reading clearly violates the > > Dewar rule (unlimited lookahead is clear nonsense) > > Well it's easy enough to implement unlimited look ahead, just not a > very good idea all things considered. remember it can't go beyond a > line mark, and reading in line by line is perfectly sensible IMO. Not that sensible, as line length is essentially unbounded. I have CSV (Comma Separated Value) files with lines of several thousand characters (a line represents a spreadsheet row, so adding additional line breaks isn't possible), and those files (full of numbers) are precisely the sort of thing that someone might want to read with Get. It obviously can be done with heroic efforts, but that is so strange that it couldn't possibly be intended. > Furthermore, I can't imagine what a "friendly" reading might be... And Tucker writes: > My interpretation is that you keep reading as long as it *might* be a numeric > literal, and if you bump into a syntax error, then you raise an exception. Which of course is precisely the reading that I have of that text (which is why I initially thought you had gotten the example wrong). This is how parsing works, and it would be beyond bizarre for Text_IO to require something else. To me, this is defining application of the Dewar rule: you have one possible reading which is clear nonsense, and one possible reading which makes perfect sense -- in such cases, you ignore the nonsense reading! Of course, there is something unusual about appealing to the Dewar rule when Dewar disagrees that it applies. :-) >, and it is not obvious to me how you write the substitute text. Probably something like Tucker's description: ...then reads the longest possible sequence of characters {that might match}[matching] the syntax of a numeric literal without a point. Possibly with an AARM note explaining the consequences. Something like: This means that you read the text so long as the input might have the syntax of a numeric literal. For instance, if the input is "2#10101T", reading stops before the 'T' and Data_Error is raised. It's not necessary to backtrack to the '#', even though the fragment "2#10101" itself does not have the syntax of a numeric literal. The fragment is potentially the first part of a numeric literal (it would be fine if the T had been a '#'), so it is all read. ... > To me this is actually something that should have been fixed probably > at this stage, since it is presumably well defined by all > implementations, not so important. Right. It's so unimportant that I put it into the AI of things we won't fix. But of course, if someone wants to take a stab at fixing some of them, it's fine by me. Are you asking that this be put on the agenda as an ultra-low priority AI? P.S. We don't actually have such a thing as "ultra-low" priority. Hopefully "low" is good enough. **************************************************************** From: Robert Dewar Sent: Thursday, December 19, 2013 9:50 PM > P.S. We don't actually have such a thing as "ultra-low" priority. > Hopefully "low" is good enough. Actually we do "pathology" :-) but you can't use that here. **************************************************************** From: Steve Baird Sent: Tuesday, October 6, 2015 12:08 PM [Editor's note: This thread is split from a thread that starts in AI12-0156-1; see the !appendix of that AI for details.] > Doesn't this already happen for renames? > i.e. > > Ref2 : access procedure (Bbb, Aaa : Integer) of X2 renames > X2(1); > > Ref2.all (Aaa => 123, Bbb => 456); -- meaning? I was wondering about that very point earlier today. What is the correct output for this example? with Text_IO; procedure Aatsor is -- anonymous access to subprogram object renaming procedure Foo (X, Y : Integer) is use Text_IO; begin Put_Line ("X =" & Integer'Image (X)); Put_Line ("Y =" & Integer'Image (Y)); end; Ref : access procedure (Aaa, Bbb : Integer := 111); Renamed_Ref : access procedure (Bbb, Aaa : Integer := 222) renames Ref; begin Ref := Foo'Access; Renamed_Ref.all (Aaa => 333); end; **************************************************************** From: Tucker Taft Sent: Tuesday, October 6, 2015 3:07 PM ... > What is the correct output for this example? Is this a trick question? To me the answer is clearly "X = 222Y = 333." **************************************************************** From: Bob Duff Sent: Tuesday, October 6, 2015 3:27 PM > Is this a trick question? When you see "baird" on the From: line, that might be a good guess. > ...To me the answer is clearly "X = 222Y = 333." But see 8.5.1(6) and 8.5.1(3). GNAT prints: X = 333 Y = 111 which seems correct. **************************************************************** From: Edmond Schonberg Sent: Tuesday, October 6, 2015 3:41 PM Correct or not, this has the feel of discriminant constraints on class-wide types :-)! The declaration provides some constants to be used later, but there is currently no mechanism to preserve those default bindings. Tuck seems to say that it is OBVIOUS that the new defaults are used. Consensus? **************************************************************** From: Tucker Taft Sent: Tuesday, October 6, 2015 4:11 PM > > When you see "baird" on the From: line, that might be a good guess. Gary clued me in on this. It is an object renaming, not a subprogram renaming, so according to 8.5.1, the subtype used is completely irrelevant, even if it happens to introduce different formal parameter names or defaults. So I agree that GNAT is doing the right thing here given the current language definition. I suppose it might be nice to give a warning when either parameter names or defaults don't agree, but that would be helpful for about 0.000001% of our users. I think we can safely wait until a well-endowed customer bumps into this and sends a nasty ticket... >> ...To me the answer is clearly "X = 222Y = 333." > > But see 8.5.1(6) and 8.5.1(3). GNAT prints: > > X = 333 > Y = 111 > > which seems correct. I agree. So "never mind" on my prior answer. The correct answer is "clearly" "X = 333Y = 111". ;-) **************************************************************** From: Randy Brukardt Sent: Tuesday, October 6, 2015 4:27 PM > Correct or not, this has the feel of discriminant constraints on > class-wide types :-)! The declaration provides some constants to be > used later, but there is currently no mechanism to preserve those > default bindings. Tuck seems to say that it is OBVIOUS that the new > defaults are used. Consensus? Consensus?? I have several different answers myself. ;-) There are probably more answers than ARG members. Tucker is clearly thinking of the subprogram renames case here. 8.5.4(7) says clearly that such a renames takes the parameter defaults from the renaming profile (not the original one). But this is an object declaration and an access type, not a subprogram renaming declaration. So I can see an argument that it ought to work like a subprogram renames. I can also see an argument that the parameter names and defaults are ignored in such a case. However, that would cause trouble for parameter passing (using the declarations of Steve's program): procedure Foo (P : access procedure (Bbb, Aaa : Integer := 222) is begin P (Aaa => 333); end Foo; Foo (Ref); Inside the subprogram, we don't know the parameter names and defaults of the original subprogram, so we had better use the new ones. Thus, I conclude that a renames ought to do so as well (to be consistent with everything else). So I guess I'm now down to one answer, and Bob and GNAT are wrong. P.S. I don't think it makes sense to use this example for or against AI12-0156-1 adding anonymous types, since it already occurs for renames and generic in out parameters (as someone sent me in private mail). Nothing new here. **************************************************************** From: Edmond Schonberg Sent: Tuesday, October 6, 2015 4:30 PM > So I guess I'm now down to one answer, and Bob and GNAT are wrong. Gary, Tuck and 8.5.1 (6/2) are of the opposite opinion, so back to two. I’d go with the RM ... **************************************************************** From: Steve Baird Sent: Tuesday, October 6, 2015 4:30 PM > Tuck seems to say that it is OBVIOUS that the new defaults are used. Tuck now says otherwise, but when I refer to "Tuck's interpretation" below, I'm talking about Tuck #1. As usual, there are two separate questions: "What does the RM say?" and "What should the RM say?" (Some might also include "Why would anyone care?"). I'll ignore the first question for now and just note that I think Tuck's interpretation works better with the use of compiler-generated renames to generate actual-to-formal bindings for the expansion of an instance of a generic. Consider that perhaps-somewhat-neglected-but-nonetheless-beloved-by-all construct, the generic in-out mode formal object of an anonymous access-to-subprogram type: declare generic Formal_Obj : in out access procedure (Aaa, Bbb : Integer := 111); procedure G; procedure G is begin Formal_Obj.all (Aaa => 333); end; Actual_Obj : access procedure (Bbb, Aaa : Integer := 222); procedure Iii is new G (Formal_Obj => Actual_Obj); procedure P (X, Y : Integer) is use Text_Io; begin Put_Line ("X =" & X'img); Put_Line ("Y =" & Y'img); end; begin Actual_Obj := P'access; Iii; end; It is not strictly a requirement, but it would certainly be nice if a compiler could implement this by introducing a renaming declaration Formal_Obj : access procedure (Aaa, Bbb : Integer := 111) renames Actual_Obj; and then replicating the body of the generic with the uses of the formal object redirected to refer to the conjured-up renaming. I think that Tuck's interpretation is needed if we want this implementation approach to work. **************************************************************** From: Randy Brukardt Sent: Tuesday, October 6, 2015 4:32 PM > > When you see "baird" on the From: line, that might be a good guess. > > Gary clued me in on this. It is an object renaming, not a subprogram > renaming, so according to 8.5.1, the subtype used is completely > irrelevant, even if it happens to introduce different formal parameter > names or defaults. So I agree that GNAT is doing the right thing here > given the current language definition. Cool. I just convinced myself that it was not. (Although that probably is a language definition problem.) > I suppose it might be nice to give a warning when either parameter > names or defaults don't agree, but that would be helpful for about > 0.000001% of our users. I think we can safely wait until a > well-endowed customer bumps into this and sends a nasty ticket... It would make more sense to declare it illegal since it would affect 0.000001% of users and it's better than renamings don't lie. Especially if we can't agree what it should do... > > > >> ...To me the answer is clearly "X = 222Y = 333." > > > > But see 8.5.1(6) and 8.5.1(3). GNAT prints: > > > > X = 333 > > Y = 111 > > > > which seems correct. > > I agree. So "never mind" on my prior answer. The correct answer is > "clearly" "X = 333Y = 111". ;-) I think you're right as the language is defined. But that's horribly misleading, given that all other uses (subprogram renames, parameter passing, etc.) work the other way. We could easily require full conformance here and get rid of this complaint (that would be incompatible, but mostly it would catch bugs, it's hard to imagine anyone intending to do this). **************************************************************** From: Randy Brukardt Sent: Tuesday, October 6, 2015 4:37 PM ... > I think you're right as the language is defined. But that's horribly > misleading, given that all other uses (subprogram renames, parameter > passing, etc.) work the other way. We could easily require full > conformance here and get rid of this complaint (that would be > incompatible, but mostly it would catch bugs, it's hard to imagine > anyone intending to do this). It's interesting that static matching of access subtypes only requires subtype conformance of the profiles, since that would seem to allow this problem in other contexts (specifically with generics). Requiring full conformance would eliminate the problem. Moral: you're nuts to use anonymous access types (outside of the hack supporting passing nested subprograms, which one can't avoid). **************************************************************** From: Jeff Cousins Sent: Tuesday, October 6, 2015 4:41 PM I've still to digest all this, but traditionally I've always pushed for full conformance, as I've known programmers get confused without it. **************************************************************** From: Bob Duff Sent: Tuesday, October 6, 2015 4:46 PM > "Why would anyone care?"). That's my view. If we had known about this in the first place, we would probably have made 8.5.1(3) require something stronger than type conformance, as suggested by Randy in another message. But at this point, I don't think it's worth fixing. **************************************************************** From: Randy Brukardt Sent: Tuesday, October 6, 2015 5:02 PM Of course, the fix is to change a single word in the RM: "subtype" => "full" in 8.5.1(4.3/2). So the risk is small. Of course, that only makes the risk/reward ratio undefined (very small/very small = could be anything because of rounding errors). I was thinking of suggesting to put this thread into the AI of things that we aren't going to fix. It's clear that there is something fishy here (since it's inconsistent with all other parts of the language), but it's probably not going to come up often enough to bother fixing. (But now we might have to argue about whether this is a bug or a feature... ;-) **************************************************************** From: Steve Baird Sent: Tuesday, October 6, 2015 5:03 PM > But at this point, I don't think it's worth fixing. Hard to argue with that. I got to looking at this issue because I was asked to look at anonymous access types in array component iterator loops and it seemed that those are similar to anonymous access types in object renamings. As noted above, I'm in favor of not making any changes to allow the array loop case. If we do that, then it would be fine with me to just let sleeping dogs lie. **************************************************************** From: Tucker Taft Sent: Tuesday, October 6, 2015 9:05 PM > It is not strictly a requirement, but it would certainly be nice if a > compiler could implement this by introducing a renaming declaration > > Formal_Obj : access procedure (Aaa, Bbb : Integer := 111) > renames Actual_Obj; > > and then replicating the body of the generic with the uses of the > formal object redirected to refer to the conjured-up renaming. > I think that Tuck's interpretation is needed if we want this > implementation approach to work. Agreed. This convinces me that the "right" answer for the reference manual is to use the new parameter names/defaults. There clearly is no other possibility within a generic, and we don't want to require full conformance on actual/formal object matching in this case, as that would interfere with "genericity" for no good reason. But I also agree that this whole topic probably deserves to be buried until some real user bumps into the problem (and it must be someone who is no relation of Steve Baird, I should probably add ;-). I don't think shifting from subtype to full conformance would be a good idea for generics, and the correspondence between object renaming and formal in out objects is a part of the language model worth preserving, I believe (AARM 12.4(1.b)). **************************************************************** From: Randy Brukardt Sent: Monday, October 12, 2015 4:37 PM ... > Agreed. This convinces me that the "right" answer for the reference > manual is to use the new parameter names/defaults. > There clearly is no other possibility within a generic, and we don't > want to require full conformance on actual/formal object matching in > this case, as that would interfere with "genericity" for no good > reason. > > But I also agree that this whole topic probably deserves to be buried > until some real user bumps into the problem (and it must be someone > who is no relation of Steve Baird, I should probably add ;-). That's what I've done with it, putting it into AI12-0066-1, the AI of issues for which the fix is as likely to cause problems as the bug. > I don't think shifting from subtype to full conformance would be a > good idea for generics, and the correspondence between object renaming > and formal in out objects is a part of the language model worth > preserving, I believe (AARM 12.4(1.b)). I don't agree, as we're talking about formal in out parameters with anonymous access-to-subprogram types. Neither of those features is used very often, and the confusion possible from allowing them to be different far outweighs any advantage simply because they're used so infrequently that no one is likely to be aware of the special rules. You'd be right if you were talking about subprogram renaming or formal subprograms, but we're not talking about those: we're talking about a pair of features that most programmers will never use by themselves, much less together. It's hard to justify making compilers do any more work than simply rejecting them if too weird. (And as always, rejecting them would allow switching to the more liberal rule in the future -- the other way around is never possible.) But of course the odds are no one will ever care no matter what choice we made, so just sticking it where the sun doesn't shine is as good as anything. :-) **************************************************************** From: Randy Brukardt Sent: Wednesday, January 11, 2017 9:39 PM I was just looking at the predicate-static rules for an unrelated reason, and it looks to me that they're too restrictive for a Boolean subtype. Specifically, the predicate-static rules only allow the current-instance to be used as one of the operands of a relational operator, the operand of a membership, or the selector of a case expression. That means that the following are illegal: subtype Fooey1 is Boolean with Static_Predicate => Fooey1; -- ERROR: subtype Fooey2 is Boolean with Static_Predicate => Fooey2 or Debug; -- ERROR: In both of these cases, the current instance is not in one of the places allowed for a predicate-static expression. One can make these legal by adding an equality operator: subtype Fooey1 is Boolean with Static_Predicate => Fooey1 = True; -- OK. subtype Fooey2 is Boolean with Static_Predicate => (Fooey2 = True) or Debug; -- OK. This sort of thing seems nearly pathological, and there is a (verbose) workaround, so I propose to file this comment into the AI of "things that we don't intend to fix" (AI12-0066-1). Any objections?? **************************************************************** From: Jean-Pierre Rosen Sent: Wednesday, January 11, 2017 11:35 PM Why not fix it? Seems harmless, and clearly an omission. What annoys me if it's not fixed is that my own programming rules forbid the use of "= True/False", so I'm unconfortable with a case that requires it. The fix would be to add a bullet after 3.2.4(15/3) saying: - The current instance BTW, I notice that "Fooey1 = True" is NOT predicate-static, because 3.2.4(20/3) says: - a call to a predefined boolean logical operator, where each operand is predicate-static; So, if "Fooey1" alone is not predicate-static, the comparison is not either! **************************************************************** From: Randy Brukardt Sent: Thursday, January 12, 2017 12:20 AM > Why not fix it? Because a predicate on a Boolean type seems like a pathology to me. What possible use is there of a subtype with one value (or no values)? (And if the predicate does not disallow a value, then it's meaningless.) I don't want to spend ARG time fixing wording that only matters for pathologies. (Bob probably would say I err too far on fixing unimportant stuff as it is.) You could also make a case that: subtype True_Only is Boolean with Static_Predicate => True_Only = True; is clearer than an alternative without the explicit "= True". (A direct test in such cases strikes me as tricky.) > Seems harmless, and clearly an omission. What annoys me if it's not > fixed is that my own programming rules forbid the use of "= > True/False", so I'm unconfortable with a case that requires it. A case that you'll never write?? > The fix would be to add a bullet after 3.2.4(15/3) saying: > - The current instance That would allow some cases that we don't really want to allow (although I'm not sure any are really problems): Fooey1 > Fooey1 Fooey1 or Fooey1 Fooey1 and then Fooey1 and the like. The rules to this point only allow a single current instance on either side of an operator. In any case, the real question is whether to fix wording for a pathology. (Or can someone find a realistic use for such a predicate??) > BTW, I notice that "Fooey1 = True" is NOT predicate-static, because > 3.2.4(20/3) says: > - a call to a predefined boolean logical operator, where each operand > is predicate-static; You're reading an ancient RM again (please get a newer one - I work hard to make these specifically so that we're all working with the latest wording). The corrigendum (AI12-0099-1) amended this bullet to say: * a call to a predefined boolean operator and, or, xor, or not, where each operand is predicate-static; > So, if "Fooey1" alone is not predicate-static, the comparison is not > either! The amended bullet makes it clear that 3.2.4(20/4) does not apply to "=". The bullet that applies is 3.2.4(19/3): * a call to a predefined equality or ordering operator, where one operand is the current instance, and the other is a static expression; That clearly applies to "Fooey1 = True". **************************************************************** From: Randy Brukardt Sent: Tuesday, March 28, 2017 12:23 AM Here's something "interesting" but we probably don't want to take any action. I tried to search for all of the places in the language were using a variable is required. Just looking for "variable" turned up 108 subclauses, so I needed a narrower search. But what? The wording isn't exactly consistent: 3.10.2(25): "If A is an access-to-variable type, then the view shall be a variable; ..." 4.1.3(13.2/2): "For a subprogram whose first parameter is of mode in out or out, or of an anonymous access-to-variable type, the prefix of any prefixed view shall denote a variable." 5.2(5/2): "The target [denoted by the variable_name] shall be a variable of a nonlimited type." 6.4.1(5): "If the mode is in out or out, the actual shall be a name that denotes a variable." 9.5(7.1/3): "If a name or prefix determines a target object, and the name denotes a protected entry or procedure, then the target object shall be a variable, ..." 12.4(7): "For a generic formal object of mode in out, the actual shall be a name that denotes a variable for which renaming is allowed (see 8.5.1)." 13.11(15): "Storage_Size or Storage_Pool may be specified for a nonderived access-to-object type via an attribute_definition_clause; the name in a Storage_Pool clause shall denote a variable." 13.11.3(5.2/4): "Otherwise, the expected type for the Default_Storage_Pool aspect is Root_Storage_Pool'Class and the aspect_definition shall be a name that denotes a variable." I gave up here, so I might have missed something with even stranger wording. If you're scoring at home, we have 3 "be a variable"s, 5 "denotes a variable"s, with two of the latter also using "be" in the wording ["be a name that denotes a variable"] while the other three don't use "be" at all. I love consistency like this. ;-) **************************************************************** From: Steve Baird (privately, thread used by permission, edited to remove chit-chat) Sent: Tuesday, July 18, 2017 11:30 AM > Never mind, I found it in 12.2(2): > > If the generic body is a child of a generic package, then its > elaboration establishes that each corresponding declaration nested in > an instance of the parent (see 10.1.1) can from then on be > instantiated without failing the Elaboration_Check. Incidentally, this wording isn't quite right. Consider how this wording applies to the elaboration of the (one and only) generic body in this example: generic package G1 is end; generic package G1.G2 is end; generic package G1.G2.G3 is pragma Elaborate_Body end; package body G1.G2.G3 is end; with G1; package I1 is new G1; with I1, G1.G2; package I2 is new I1.G2; with I2, G1.G2.G3; package I3 is new I2.G3; I3 is instantiating I2.G3 after the body of G1.G2.G3 has been elaborated. We want the elaboration check to pass, but does this follow from a strict reading of the wording? In this context, the phrase "the parent" obviously refers to G1.G2. There are no instances of G1.G2 anywhere in this example. There is an instance of I1.G2, but that's not the same thing. **************************************************************** From: Randy Brukardt Sent: Tuesday, July 18, 2017 12:39 PM You are right, seems like an ancestor or something. A fix is not clear to me (if it was, I'd suggest fixing it, but otherwise just leave it until it matters in practice). **************************************************************** From: Steve Baird Sent: Tuesday, July 18, 2017 1:23 PM If we actually wanted to fix this, I'd suggest defining a new term. The "ultimate corresponding generic unit" of a generic unit G is defined to be something like If G is declared in an instance of another generic unit G2, then the ultimate corresponding generic unit of G2.G; otherwise G. The precise name of the term is, as always, up for discussion. Then the present wording could be fixed to use this new term: If the generic body is a child of a generic package (see 10.1.1), then its elaboration establishes that any generic unit whose ultimate corresponding generic unit is that child unit can from then on be instantiated without failing the Elaboration_Check. **************************************************************** From: Steve Baird Sent: Tuesday, July 18, 2017 5:41 PM My use of G2.G wasn't quite right. The notion of the corresponding generic declared within the outer generic would have to be spelled out more explicitly to cope with something like generic package G1 is package Nested_Nongeneric is generic package G2 is end; end; end; package I1 is new G2; package I2 is new I1.Nested_Nongeneric.G2; where the name G1.G2 makes no sense. But you get the idea. As you pointed out earlier, the real question is whether this is worth fixing at all. I think leaving wording as is and adding an AARM note might be a reasonable choice, but even that is a tough call. If it ain't (sufficiently) broke ... **************************************************************** From: Randy Brukardt Sent: Wednesday, July 19, 2017 10:50 AM Maybe we should put file this thread in the AI of things we don't intend to fix?? **************************************************************** From: Steve Baird Sent: Wednesday, July 19, 2017 11:03 AM That sounds good to me. **************************************************************** From: Randy Brukardt Sent: Wednesday, June 10, 2020 7:42 PM There doesn't seem to be any definition of the nominal subtype of an aggregate in the Standard. We have tried to ensure that all constructs have nominal subtypes, and as far as I can tell, an aggregate is pretty much the only construct that doesn't have one. (There were some index entries missing for those definitions, but that's not normative in any way.) Tucker points out that it doesn't appear to matter at the moment, since all known uses of "nominal subtype" involve names, and the only way to make an aggregate a name is to qualify it (which gives it a "nominal subtype"). I still worry that we are headed for trouble in this area. Most likely, we would want the nominal subtype of an (un-qualified) aggregate to be an unconstrained view of the expected type. The actual bounds and discriminants come from the aggregate value itself. Is this worth fixing, or should we stick this into the "if it ain't broke, don't fix it" AI?? **************************************************************** From: Tucker Taft Sent: Wednesday, June 10, 2020 7:50 PM > Most likely, we would want the nominal subtype of an (un-qualified) > aggregate to be an unconstrained view of the expected type. The actual > bounds and discriminants come from the aggregate value itself. For a tagged type, it doesn't want to be unconstrained, it wants to be the first subtype. But as indicated above, I don't think we need a nominal subtype for anything that is not syntactically a "name". > Is this worth fixing, or should we stick this into the "if it ain't > broke, don't fix it" AI?? I am currently in favor of the latter, but I'll wait until Steve's Brain takes a shot at the issue... ;-) **************************************************************** From: Randy Brukardt Sent: Thursday, July 2, 2020 9:01 PM ... > > Most likely, we would want the nominal subtype of an (un-qualified) > > aggregate to be an unconstrained view of the expected type. The > > actual bounds and discriminants come from the aggregate value itself. > > For a tagged type, it doesn't want to be unconstrained, it wants to be > the first subtype. But as indicated above, I don't think we need a > nominal subtype for anything that is not syntactically a "name". Steve pointed out privately that 3.3 says: At the place where a view of an object is defined, a nominal subtype is associated with the view ... and that 4.3(5) states that an aggregate is a view of an object. This means that either we ought to have a nominal subtype for an aggregate or qualify 3.3 somehow. > > Is this worth fixing, or should we stick this into the "if it ain't > > broke, don't fix it" AI?? > > I am currently in favor of the latter, but I'll wait until Steve's > Brain takes a shot at the issue... ;-) My guess is that it doesn't matter today, but it is likely to in the future. For instance, we have a HELD proposal to extend case statements to record types. One would need to know the nominal subtype of any possible expression in that case in order to properly make a completeness check for the case statement. As such, I think we at a minimum need to document that there is a hole, but patching the hole could wait for a future update (or Steve's Brain to come up with something important). **************************************************************** From: Tucker Taft Sent: Friday, July 3, 2020 9:32 AM As I suggested, before defining a nominal subtype, we need to know who might care. You are suggesting a possible use in a case statement, so we really want the nominal subtype to be as "tight" as possible, to avoid having to always have "when others." So I think it definitely wants to be constrained whenever possible. **************************************************************** From: Randy Brukardt (privately) Sent: Friday, September 4, 2020 In an ARG thread about Unchecked_Union, we had the following example: with Ada.Text_IO; procedure Unchecked_Union_No_Default_Test is type Precision is (Single_Precision, Multiple_Precision); type Number (Kind : Precision) is record case Kind is when Single_Precision => SP_Value : Long_Float; when Multiple_Precision => MP_Value_Length : Integer; MP_Value_First : access Long_Float; end case; end record; pragma Unchecked_Union (Number); Y : Number (Single_Precision); -- Inferable discriminant begin Y.SP_Value := 55.7; if Y = (Single_Precision, 45.6) then -- (1) Ada.Text_IO.Put_Line ("Y is single 45.6"); else Ada.Text_IO.Put_Line ("Y isn't single 45.6"); end if; end Unchecked_Union_No_Default_Test; The claim was made that (1) should raise Program_Error as the aggregate does not have inferrable discriminants. An object has inferrable discriminants if it has a constrained nominal subtype. (B.3.3(20/2)). An aggregate is an object by 3.3(11). So we need to know the nominal subtype of the aggregate to answer (1) definitively. This is nowhere near an intended use for an unchecked union, so it doesn't really matter, but it does show how these definitions tend to pop up in unusual places. (And there is a "known rule" that depends on the nominal subtype of an aggregate, even though that rule is rather a pathological case.) ****************************************************************