!standard 3.10.2(19.2/4) 15-03-27 AI05-0157-1/02 !standard 3.10.2(19.3/4) !standard 4.3.3(11/2) !standard 6.8(2/3) !standard 6.8(3/3) !standard 6.8(5/3) !standard 6.8(6/3) !standard 6.8(7/3) !standard 7.5(2.9/3) !standard 13.14(5.1/4) !standard 13.14(5.2/4) !standard 13.14(8/3) !standard 13.14(10.1/3) !standard 13.14(10.2/3) !standard 13.14(10.3/3) !class binding interpretation 15-03-23 !status Corrigendum 2015 15-03-26 !status ARG Approved 8-0-2 15-03-26 !status work item 15-03-23 !status received 15-02-26 !priority Low !difficulty Easy !qualifier Omission !subject Missing rules for expression functions !summary (1) Expression functions can directly use an aggregate as well as an expression surrounded by parentheses. (2) The expression or aggregate of an expression function has a defined applicable index constraint. (3) The statically deeper relationship is defined as for a return statement for the expression or aggregate of an expression function. !question (1) If an expression function needs to return an aggregate, the syntax requires double parens: function Rounds return VExt is ((F732C00.Rounds with H => CNPriv)); as the syntax is [overriding_indicator] function_specification is (expression) [aspect_specification]; and an aggregate is also surrounded by parentheses. This is ugly, and inconsistent with the rest of Ada. In particular, it is inconsistent with the behavior of aggregates in qualified expressions and allocators, and the behavior of other things surrounded in parentheses like conditional expressions and raise expressions. Should aggregates be allowed here? (Yes.) (2) 4.3.3(11/2) defines the applicable index constraint of an aggregate in many contexts. We surely want the return version to apply to an expression function as well, but it's not clear that the wording has that effect. We define an expression function dynamically to be equivalent to the execution of a simple_return_statement, but we treat the legality and static semantic rules explicitly in 6.8. 4.3.3(11/2) is a Legality Rule, thus it arguably is not covered by 6.8(7/3). Should it be updated to include expression functions? (Yes.) (3) 3.10.2(19.2/4) and 3.10.2(19.3/4) define the statically deeper relationship for return statements inside a function. The same rules need to apply within an expression function. (Note that we don't need to make any changes to the dynamic accessibility level, such as 3.10.2(10.8/3), since 6.8(7/3) clearly does apply to runtime effects.) Should this be fixed? (Yes.) !recommendation (See Summary.) !wording Modify 3.10.2(19.2/4) [as modified by AI12-0089-1]: * Inside a return statement that applies to a function or generic function F{, or the return expression of an expression function F}, when determining whether the accessibility level of an explicitly aliased parameter of F is statically deeper than the level of the return object of F, the level of the return object is considered to be the same as that of the level of the explicitly aliased parameter; for statically comparing with the level of other entities, an explicitly aliased parameter of F is considered to have the accessibility level of the body of F. Modify 3.10.2(19.3/4) [as modified by AI12-0089-1]: * For determining whether a level is statically deeper than the level of the anonymous access type of an access result of a function, when within a return statement that applies to the function {or the return expression of expression function @i}, the level of the master of the call is presumed to be the same as that of the level of the master that elaborated the function body. [Editor's note: I considered added an equivalence rule for the statically deeper relationship instead, either here or in 6.8, but that didn't seem to simplify anything, and having it in 6.8 potentially would cause someone to think that it wasn't defined (we want all of the rules for accessibility in the "Heart of Darkness"; it's hard enough to understand without having to jump all over the place to get the complete picture).] Modify 4.3.3(11/2): * For an explicit_actual_parameter, an explicit_generic_actual_parameter, the expression of a return statement{, the return expression of an expression function}, the initialization expression in an object_declaration, or a default_expression [(for a parameter or a component)], when the nominal subtype of the corresponding formal parameter, generic formal parameter, function return object{, expression function return object}, object, or component is a constrained array subtype, the applicable index constraint is the constraint of the subtype; Replace 6.8(2/3) by: expression_function_declaration ::= [overriding_indicator] function_specification is (expression) [aspect_specification]; | [overriding_indicator] function_specification is aggregate [aspect_specification]; Modify 6.8(3/3): The expected type for the expression or aggregate of an expression_function_declaration is the result type (see 6.5) of the function. Modify 6.8(5/3): If the result subtype has one or more unconstrained access discriminants, the accessibility level of the anonymous access type of each access discriminant, as determined by the expression {or aggregate} of the {expression_function_declaration}[expression function], shall not be statically deeper than that of the master that elaborated the expression_function_declaration. Modify 6.8(6/3): An expression_function_declaration declares an *expression function*. {The *return expression* of an expression function is the expression or aggregate of the expression_function_declaration.} A completion is not allowed for an expression_function_declaration; however, an expression_function_declaration can complete a previous declaration. Modify 6.8(7/3): The execution of an expression function is invoked by a subprogram call. For the execution of a subprogram call on an expression function, the execution of the subprogram_body executes an implicit function body containing only a simple_return_statement whose expression is [that]{the return expression} of the expression function. Modify 7.5(2.9/3): * the {return} expression of an {expression function}[expression_function_declaration] (see 6.8) [Editor's note: AARM 8.3(29.ee/3) also needs a similar update.] Modify 13.14(5.1/4) [added by AI12-0103-1]: * At the occurrence of an expression_function_declaration that is a completion, the {return} expression of the expression function causes freezing. Modify 13.14(5.2/4) [added by AI12-0132-1]: * At the occurrence of a renames-as-body whose callable_entity_name denotes an expression function, the {return} expression of the expression function causes freezing. Modify 13.14(8/3): A static expression (other than within an aspect_specification) causes freezing where it occurs. An object name or nonstatic expression causes freezing where it occurs, unless the name or expression is part of a default_expression, a default_name, the {return} expression of an expression function, an aspect_specification, or a per-object expression of a component's constraint, in which case, the freezing occurs later as part of another construct or at the freezing point of an associated entity. Modify 13.14(10.1/3): * At the place where a function call causes freezing, the profile of the function is frozen. Furthermore, if a parameter of the call is defaulted, the default_expression for that parameter causes freezing. If the function call is to an expression function, the {return} expression of the expression function causes freezing. [Editor's note: AARM 13.14(10.g/4) also needs a similar update.] Modify 13.14(10.2/3): * At the place where a generic_instantiation causes freezing of a callable entity, the profile of that entity is frozen unless the formal subprogram corresponding to the callable entity has a parameter or result of a formal untagged incomplete type; if the callable entity is an expression function, the {return} expression of the expression function causes freezing. Modify 13.14(10.3/3): * At the place where a use of the Access or Unchecked_Access attribute whose prefix denotes an expression function causes freezing, the {return} expression of the expression function causes freezing. !discussion (1) Consistency with qualified expressions seems important here. An early implementation of Ada 2012 allows this syntax (presumably by accident), and an ACATS test-writer used it (definitely by accident, known because the author of this AI and that that test-writer are one and the same). It seems natural, and it's best if the syntax of Ada follows that as much as possible. (2) It appears that a strict reading of 4.3.3 says that function Cool return Some_Array is ((others => 1)); or, with adoption of (1) function Cool return Some_Array is (others => 1); are illegal because an "applicable index constraint" isn't provided (this is none of the contexts listed in 4.3.3(11-15.1)). We don't want that, since the equivalent function Cool return Some_Array is begin return (others => 1); end Cool; is legal. (3) This was raised by Steve Baird (who else?). It is unlikely but possible for these 3.10.2 rules to matter. They would matter in a case like: function Bar (Obj : aliased in out Int_Cont; Index : in Natural) return access Integer is (Obj.Element(Index)'Access); We want this to be legal, as it is legal if this is written with an explicit body. (Bar here is similar to the construction of function Reference in the containers; we would want it to be possible for an expression function to be used in place of a full body for these routines.) !corrigendum 3.10.2(19.2/4) @drepl @xbullet, when determining whether the accessibility level of an explicitly aliased parameter of @i is statically deeper than the level of the return object of @i, the level of the return object is considered to be the same as that of the level of the explicitly aliased parameter; for statically comparing with the level of other entities, an explicitly aliased parameter of @i is considered to have the accessibility level of the body of @i.> @dby @xbullet, or the return expression of an expression function @i, when determining whether the accessibility level of an explicitly aliased parameter of @i is statically deeper than the level of the return object of @i, the level of the return object is considered to be the same as that of the level of the explicitly aliased parameter; for statically comparing with the level of other entities, an explicitly aliased parameter of @i is considered to have the accessibility level of the body of @i.> !corrigendum 3.10.2(19.3/4) @drepl @xbullet, when within a return statement that applies to @i, the level of the master of the call is presumed to be the same as that of the level of the master that elaborated the body of @i.> @dby @xbullet, when within a return statement that applies to @i or the return expression of expression function @i, the level of the master of the call is presumed to be the same as that of the level of the master that elaborated the body of @i.> !corrigendum 4.3.3(11/2) @drepl For an @fa, an @fa, the @fa of a return statement, the initialization expression in an @fa, or a @fa (for a parameter or a component), when the nominal subtype of the corresponding formal parameter, generic formal parameter, function return object, object, or component is a constrained array subtype, the applicable index constraint is the constraint of the subtype; @dby For an @fa, an @fa, the @fa of a return statement, the return expression of an expression function, the initialization expression in an @fa, or a @fa (for a parameter or a component), when the nominal subtype of the corresponding formal parameter, generic formal parameter, function return object, expression function return object, object, or component is a constrained array subtype, the applicable index constraint is the constraint of the subtype; !corrigendum 6.8(2/3) @drepl @xcode<@fa@b<@ft>@fa< (expression) [aspect_specification];>> @dby @xcode<@fa@b<@ft>@fa< (expression) [aspect_specification]; | [overriding_indicator] function_specification >@b<@ft>@fa< aggregate [aspect_specification];>> !corrigendum 6.8(3/3) @drepl The expected type for the @fa of an @fa is the result type (see 6.5) of the function. @dby The expected type for the @fa or @fa of an @fa is the result type (see 6.5) of the function. !corrigendum 6.8(5/3) @drepl If the result subtype has one or more unconstrained access discriminants, the accessibility level of the anonymous access type of each access discriminant, as determined by the @fa of the expression function, shall not be statically deeper than that of the master that elaborated the @fa. @dby If the result subtype has one or more unconstrained access discriminants, the accessibility level of the anonymous access type of each access discriminant, as determined by the @fa or @fa of the @fa, shall not be statically deeper than that of the master that elaborated the @fa. !corrigendum 6.8(6/3) @drepl An @fa declares an @i. A completion is not allowed for an @fa; however, an @fa can complete a previous declaration. @dby An @fa declares an @i. The @i of an expression function is the @fa or @fa of the @fa. A completion is not allowed for an @fa; however, an @fa can complete a previous declaration. !corrigendum 6.8(7/3) @drepl The execution of an expression function is invoked by a subprogram call. For the execution of a subprogram call on an expression function, the execution of the @fa executes an implicit function body containing only a @fa whose @fa is that of the expression function. @dby The execution of an expression function is invoked by a subprogram call. For the execution of a subprogram call on an expression function, the execution of the @fa executes an implicit function body containing only a @fa whose @fa is the return expression of the expression function. !corrigendum 7.5(2.9/3) @drepl @xbullet of an @fa (see 6.8)> @dby @xbullet !corrigendum 13.14(5.1/4) @drepl @xbullet that is a completion, the @fa of the expression function causes freezing.> @dby @xbullet that is a completion, the return expression of the expression function causes freezing.> !corrigendum 13.14(5.2/4) @drepl @xbullet@fa denotes an expression function, the @fa of the expression function causes freezing.> @dby @xbullet@fa denotes an expression function, the return expression of the expression function causes freezing.> !corrigendum 13.14(8/3) @drepl A static expression (other than within an @fa) causes freezing where it occurs. An object name or nonstatic expression causes freezing where it occurs, unless the name or expression is part of a @fa, a @fa, the @fa of an expression function, an @fa, or a per-object expression of a component's @fa, in which case, the freezing occurs later as part of another construct or at the freezing point of an associated entity. @dby A static expression (other than within an @fa) causes freezing where it occurs. An object name or nonstatic expression causes freezing where it occurs, unless the name or expression is part of a @fa, a @fa, the return expression of an expression function, an @fa, or a per-object expression of a component's @fa, in which case, the freezing occurs later as part of another construct or at the freezing point of an associated entity. !corrigendum 13.14(10.1/3) @drepl @xbullet for that parameter causes freezing. If the function call is to an expression function, the @fa of the expression function causes freezing.> @dby @xbullet for that parameter causes freezing. If the function call is to an expression function, the return expression of the expression function causes freezing.> !corrigendum 13.14(10.2/3) @drepl @xbullet causes freezing of a callable entity, the profile of that entity is frozen unless the formal subprogram corresponding to the callable entity has a parameter or result of a formal untagged incomplete type; if the callable entity is an expression function, the @fa of the expression function causes freezing.> @dby @xbullet causes freezing of a callable entity, the profile of that entity is frozen unless the formal subprogram corresponding to the callable entity has a parameter or result of a formal untagged incomplete type; if the callable entity is an expression function, the return expression of the expression function causes freezing.> !corrigendum 13.14(10.3/3) @drepl @xbullet denotes an expression function causes freezing, the @fa of the expression function causes freezing.> @dby @xbullet denotes an expression function causes freezing, the return expression of the expression function causes freezing.> !ASIS The ASIS operations for expression functions (whatever they are) will need to allow aggregates. Can't be more specific than that as the previous is not well-defined. For (2) and (3), there is no ASIS effect. !ACATS test Problem (1) originated in ACATS test B732C01, so we already have an example. It would be nice for it to be used in an ACATS C-Test, but it's unlikely to not work. It would be nice to have tests for examples like the ones in the discussion for problems (2) and (3). !appendix From: Randy Brukardt Sent: Thursday, February 26, 2015 4:07 PM I've been sitting on this one for the last few days, both because I wasn't sure what to think and because I didn't want to make even more work for myself before the call. Since we decided to have another call next month to finish up, I figured I better raise this, especially as I've decided what I think. In an ACATS B-Test (based on Jeff's C-Tests for type invariants), I needed some convenient function bodies, so I used expression functions: function Rounds return VExt is (F732C00.Rounds with H => CNPriv); This is an extension aggregate. GNAT happily compiles the test and reports the proper errors. However, my new Janus/Ada reports syntax errors on this test (it suggests moving the right paren from the end to before the with). The Ada grammar for expression functions is: expression_function_declaration ::= [overriding_indicator] function_specification is (expression) [aspect_specification]; An aggregate is an expression for this purpose, so the grammar requires enclosing it in a double set of parens: function Rounds return VExt is ((F732C00.Rounds with H => CNPriv)); My initial reaction was of course that GNAT was wrong, but upon reflection, there is a reasonable argument that the standard is wrong instead: (1) In similar cases (conditional expressions, qualified expressions), we go to lengths to ensure that double parens are not needed. (2) I wrote the above naturally (it didn't directly have anything to do with the test), so one can presume that at least some other Ada programmers would also expect the above to work. "It feels right." Obviously, whoever implemented that in GNAT thought the same way. (This was the point that I was wavering on, primarily because I thought that Jeff had written the test in question. There is a visceral difference between someone else accidentally misusing a feature and one's self doing the same. ;-) (3) The double parens are UGLY!!! :-) The above suggests that we should change the expression function syntax a-la the similar syntax for qualified expressions: expression_function_declaration ::= [overriding_indicator] function_specification is (expression) [aspect_specification]; | [overriding_indicator] function_specification is aggregate [aspect_specification]; A bunch of the text also would need change (to "expression or aggregate"). Alternatively, we could add a new non-terminal to mean "(expression) or aggregate" and use that in the grammar and text. Thoughts?? --- A vaguely related question. 4.3.3(11/2) defines the applicable index constraint of an aggregate in many contexts. We surely want the return version to apply to an expression function as well, but it's not clear to me that the wording has that effect. We define an expression function dynamically to be equivalent to the execution of a simple_return_statement, but we treat the legality and static semantic rules explicitly in 6.8. 4.3.3(11/2) is a Legality Rule, thus it arguably is not covered by 6.8(7/3), particularly in cases where legality is involved (for instance, whether an others choice is allowed). Specifically, it appears that a strict reading says that function Cool return Some_Array is ((others => 1)); is illegal because an "applicable index constraint" isn't provided (this is none of the contexts listed in 4.3.3(11-15.1)). That seems to violate the Dewar rule, since function Cool return Some_Array is begin return (others => 1); end Cool; is legal. Probably we should add some wording somewhere to fix this. **************************************************************** From: Robert Dewar Sent: Thursday, February 26, 2015 4:21 PM > A bunch of the text also would need change (to "expression or aggregate"). > Alternatively, we could add a new non-terminal to mean "(expression) > or aggregate" and use that in the grammar and text. > > Thoughts?? I agree, the double parens are ugly, and we should avoid them here **************************************************************** From: Gary Dismukes Sent: Thursday, February 26, 2015 4:29 PM ... > Thoughts?? Agreed that this should be fixed, and your suggestion for changing the syntax seems reasonable. Even more so since GNAT already supports this. ;-) ... > Probably we should add some wording somewhere to fix this. I agree with this suggested change as well. **************************************************************** From: Tucker Taft Sent: Thursday, February 26, 2015 8:26 PM > ... My initial reaction was of course that GNAT was wrong, but upon > reflection, there is a reasonable argument that the standard is wrong instead: > > (1) In similar cases (conditional expressions, qualified expressions), > we go to lengths to ensure that double parens are not needed. Also in qualified expressions, we allow a parenthesized expression or an aggregate. > A bunch of the text also would need change (to "expression or aggregate"). > Alternatively, we could add a new non-terminal to mean "(expression) > or aggregate" and use that in the grammar and text. I could see having a non-terminal for: (expression) | aggregate | (conditional_expression) | (quantified_expression) perhaps "parenthesized_expression" ;-) While we are at it, I presume "T'(if A then X else Y)" is legal due to the rules that allow the elimination of extra parenthesizes around conditional_expressions, but it seems like we could define qualified_expression as subtype_mark'parenthesized_expression (or whatever we end up calling this new non-terminal) and avoid the need to apply the special parenthesis elimination rule in this context. > Thoughts?? I agree we don't want to require double parentheses here. > > --- > > A vaguely related question. 4.3.3(11/2) defines the applicable index > constraint of an aggregate in many contexts. We surely want the return > version to apply to an expression function as well, but it's not clear > to me that the wording has that effect. ... > > Probably we should add some wording somewhere to fix this. Agreed. **************************************************************** From: Jean-Pierre Rosen Sent: Friday, February 27, 2015 2:43 AM > A bunch of the text also would need change (to "expression or aggregate"). > Alternatively, we could add a new non-terminal to mean "(expression) > or aggregate" and use that in the grammar and text. > > Thoughts?? The syntax for aggregates was designed at a time when it was the only case of required double parentheses. Then, we had conditional expressions, with explicit wording to avoid double parentheses. Now the expression functions... Isn't it time that we bite the bullet and have some wording (or syntax, I don't know) to state that double parentheses are never required in Ada, so this problem wouldn't appear any more in future additions to the language? **************************************************************** From: Robert Dewar Sent: Friday, February 27, 2015 2:56 AM That seems wrong X ((1,2,3)) can have a totally different meaning from X (1,2,3) where X are overloaded subprograms **************************************************************** From: Jean-Pierre Rosen Sent: Friday, February 27, 2015 3:22 AM Right. What about: double parentheses are never required if the type is determined from context ? **************************************************************** From: Bob Duff Sent: Friday, February 27, 2015 9:49 AM > An aggregate is an expression for this purpose, so the grammar > requires enclosing it in a double set of parens: > > function Rounds return VExt is ((F732C00.Rounds with H => > CNPriv)); ... > The above suggests that we should change the expression function > syntax a-la the similar syntax for qualified expressions: I agree we should not require double parens in this case. > expression_function_declaration ::= > [overriding_indicator] function_specification is (expression) > [aspect_specification]; > | [overriding_indicator] function_specification is aggregate > [aspect_specification]; > > A bunch of the text also would need change (to "expression or aggregate"). > Alternatively, we could add a new non-terminal to mean "(expression) > or aggregate" and use that in the grammar and text. I count six such places (searched for expression function). Not so horrible. Or we could say, The term "expression of an expression function" refers to the expression or aggregate of the expression_function_declaration. ^^^^^^^^^^ ...and put that one in syntax font. echoing 4.4(1). Tucker wrote: > I could see having a non-terminal for: > > (expression) | aggregate | (conditional_expression) | > (quantified_expression) > > perhaps "parenthesized_expression" ;-) I agree that's cleaner in some ways, but it seems like a bigger change than necessary. > While we are at it, I presume "T'(if A then X else Y)" is legal due to > the rules that allow the elimination of extra parenthesizes around > conditional_expressions,... Yes, that's legal. >...but it seems > like we could define qualified_expression as >subtype_mark'parenthesized_expression > (or whatever we end up calling this new non-terminal) and avoid the >need to apply the special parenthesis elimination rule in this context. That seems like a gratuitous change at this point. If it eliminated the need for the special paren-elimination rules, it might be worth it, but eliminating those rules just for qual_exp doesn't gain us anything. Also, if we go that way, there's a possible confusion between "parenthesized_expression" and "parenthesized expression". The latter is used 10 times, and "parenthesized" is used 24 times, and it's not formally defined, which is just fine in the absence of this new parenthesized_expression nonterminal. My mental model of Ada contains this syntax rule: parenthesized_expression ::= (expression) which is not in the RM. ;-) **************************************************************** From: Bob Duff Sent: Friday, February 27, 2015 9:42 AM > Right. What about: > double parentheses are never required if the type is determined from > context ? It is important that aggregates be detected syntactically. We really don't want to mix semantics into that (e.g. if X(1,2,3) is allowed when there is just one X that takes one parameter). That would damage readability IMHO, and would be an earthquake for compilers. Besides, this syntax goes back to Ada 83, and I haven't heard any complaints from users. **************************************************************** From: Robert Dewar Sent: Friday, February 27, 2015 9:58 AM > It is important that aggregates be detected syntactically. > We really don't want to mix semantics into that (e.g. if > X(1,2,3) is allowed when there is just one X that takes one > parameter). That would damage readability IMHO, and would be an > earthquake for compilers. I strongly agree, let's leave aggregates alone in this discussion. Aggregates always require a level of parens that is part of the aggregate, we have been used to this for 20 years, and we should not even consider a change. > Besides, this syntax goes back to Ada 83, and I haven't heard any > complaints from users. Exactly! **************************************************************** From: Randy Brukardt Sent: Friday, February 27, 2015 3:32 PM ... > > A bunch of the text also would need change (to "expression or aggregate"). > > Alternatively, we could add a new non-terminal to mean "(expression) > > or aggregate" and use that in the grammar and text. > > I count six such places (searched for expression function). > Not so horrible. Right, pretty mechanical to change. I just wanted to note that it would need to be done (the change is more than just adding the production in question). > Or we could say, > > The term "expression of an expression function" refers to the > expression or aggregate of the expression_function_declaration. > ^^^^^^^^^^ > ...and put that one in syntax font. > > echoing 4.4(1). I don't think we want to introduce any more cases into the RM where the English text means something subtly different than the syntax term. After all, we already have body (syntax font) /= body (text font) /= body (keyword font). And we had to add some weasel wording so that "function_call" (syntax font) = "function call" (text font), else everything using the former did not allow infix operators! Your proposal that "expression (text font) of an expression function" means something different than "expression (syntax font) of an expression function" falls into the category. Of course, there's an argument that "expression" (text font) already means something subtly different than "expression" syntax font (the former generally is taken to include things that aren't technically expressions, like simple_expressions and choice_expressions -- indeed I used it that way in one place in yesterday's approved changes). So it's not a terrible idea. But given that we have to change all of the wording either way, I'd probably say just use "expression or aggregate" and avoid introducing yet another term. Especially if there's only six places. Didn't you (Bob) write a message complaining about introducing excessive terms earlier this week? **************************************************************** From: Robert Dewar Sent: Friday, February 27, 2015 3:38 PM Boy this reminds me of a discussion in the Algol-68 maintenance committee where the font of a comma made a critical difference :-) ****************************************************************