!standard 4.9(16) 19-03-11 AI12-0322-1/04 !standard 5.2.1(4/5) !standard 5.2.1(5/5) !class Amendment 19-03-07 !status Amendment 1-2012 19-03-11 !status ARG Approved 10-0-0 19-03-11 !status work item 19-03-07 !status received 19-03-07 !priority Low !difficulty Easy !subject Equivalence for the target name symbol !summary Replace the equivalence for the target name symbol with some rules. !problem The equivalence for the target name symbol seems very complicated, verging on incomprehensible. !proposal (See Summary.) !wording Add after 4.9(16): * It is a target_name (see 5.2.1) in an assignment_statement whose /variable_/name statically denotes some entity; Modify AARM 5.2.1(3.a/5): The complete context rule is formally given in 8.6. The constant view rule is formally given in 3.3; the nominal subtype {is a property taken from the target object as described below in Dynamic Semantics}[follows from the equivalence given below in Static Semantics]. Modify 5.2.1(4/5): A target_name shall [only] appear {only} in the expression of an assignment_statement. [Editor's note: Bob suggested this small rewording. Since the original AI is WG9-approved, the change has to go in *some* AI, and this one was handy and relevant.] Replace 5.2.1 (5/5) with: Dynamic Semantics For the execution of an assignment_statement with one or more target_names appearing in its expression, the /variable_/name V of the assignment_statement is evaluated first to determine the object denoted by V, and then the expression of the assignment_statement is evaluated with the evaluation of each target_name yielding a constant view of the the target whose properties are otherwise identical to those of the view provided by V. The remainder of the execution of the assignment_statement is as given in subclause 5.2. AARM Ramification: Use of a target_name can be erroneous if the /variable_/name V is a discriminant-dependent component, and some other constituent of the expression modifies the discriminant governing the component V. The assignment probably would be erroneous anyway, but the use of a target_name eliminates the possibility that a later evaluation of V raises an exception before any erroneous execution occurs. See 3.7.2. !discussion We are replacing the old equivalence which was based on an implicit procedure, with an explicit dynamic semantics defining what it means to evaluate a target_name. We add a definition of statically denotes for the target_name, so that the anti-order-dependence rules of 6.4.1 can see through @. Presumably, there are other rules that would be helped as well. !ASIS No change is needed (this AI is not adding any new capabilities; AI12-0125-3 should describe the ASIS changes needed to support target name symbols). !ACATS test ACATS B- and C-Tests are needed to check that the new capabilities are supported. !corrigendum 4.9(16) @dinsa @xbullet whose @fa statically denotes some entity; or> @dinst @xbullet (see 5.2.1) in an @fa whose @i@fa statically denotes some entity; or> !corrigendum 5.2.1(0) @dinsc Just to force a conflict; the actual changes are found in the conflict file. !appendix From: Randy Brukardt Sent: Wednesday, March 6, 2019 4:46 PM Bob's RM review includes the following: >5.2.1(5/5): >[The variable_name is evaluated only once.] In particular, if a >target_name with nominal subtype S appears in the expression of an >assignment_statement A, then A is equivalent to a call on a local >anonymous procedure with the actual parameter being the variable_name >of A, where the local anonymous procedure has an in out parameter with >unique name P of subtype S, with a body being A with the variable_name >being replaced by P, and any target_names being replaced by the >qualified expression S'(P). >That looks like Steve's handiwork. ;-) Just say "A target_name denotes >the value of the variable_name (before the assignment). The >variable_name is evaluated only once." >All this business about anonymous procedures is totally >incomprehensible. Or at least move it to the AARM. > >Not sure "(before the assignment)" is necessary -- seems pretty obvious. > >Also, this is about "evaluation", so shouldn't it be under Dynamic >Semantics? I don't know how to handle this one. My first inclination is to ignore it -- this topic was fairly throughly hashed over during the discussion of this AI. But that doesn't seem to be appropriate. So let me explain this a bit and ruminate over options. The reason for all of this babble is to clearly define what happens in various corner cases. Without it, we're leaving lots of semantics undefined, and there are questions about Legality, accessibility, finalization, and erroneousness that are left unanswered. For instance, this model defines how @ is handled for the anti-order-dependence Legality Rules. It defines what happens if a discriminant governing the target is changed by the expression. It defines what happens to the value of the target itself is changed by the expression. It defines how @ is finalized (it isn't). And probably a bunch of other things I haven't thought of (and perhaps that no one has thought of)). We talked about defining all of these things explicitly, but it seems like it would require a lot of duplication and wording. And, unlike parens, we can't really get away without some definition, since there is no intuitive answer that applies (especially in corner-cases). Additionally, an equivalence rule like this allows us to be certain that we can answer any weird case that Steve can come up with; explicit rules can't do that. So, is there any other viable suggestion, or should I ignore this comment? Or do I have to put it on the agenda?? *************************************************************** From: Tucker Taft Sent: Wednesday, March 6, 2019 5:07 PM I think should go on the agenda, but with a time-limited discussion. It would *really* help if Bob and/or Steve could identify exactly what problems Steve's wording solves, i.e., what corner cases are not covered by Bob's wording. If they are extremely rare, then a "To Be Honest" might be the right choice. *************************************************************** From: Randy Brukardt Sent: Wednesday, March 6, 2019 5:38 PM > I think should go on the agenda, but with a time-limited discussion. 10 seconds? :-) > It would *really* help if Bob and/or Steve could identify exactly what > problems Steve's wording solves, i.e., what corner cases are not > covered by Bob's wording. If they are extremely rare, then a "To Be > Honest" might be the right choice. I listed some of them in my original note: (1) What happens if the target is modified by evaluating the expression? Glob : Natural := 0; function Side_Effect return Natural is begin Glob := Glob + 1; return 1; end Side_Effect; Glob := @ + Side_Effect; Steve's wording says that Glob = 1 after this call, regardless of when Side_Effect is evaluated. Bob's wording leaves it unspecified (because it leaves *everything* unspecified). (2) What happens if the target is discriminant-dependent and the discriminant is changed? Glob.F := @ + Change_Glob; Steve's wording says this is erroneous (by the rule that says doing this to a parameter is erroneous), Bob's wording says nothing. (3) How is the anti-order-dependence rules enforced? Targ := @.F + Func_with_In_Out (@.F.all); Steve's wording gives an unequivocal answer, no idea for Bob's (since it says nothing about anything). *************************************************************** From: Steve Baird Sent: Wednesday, March 6, 2019 5:41 PM >> All this business about anonymous procedures is totally >> incomprehensible. Or at least move it to the AARM. Guilty as charged (and unrepentant). We want the rules to correctly handle cases where the evaluation of the RHS modifies the LHS, as well as all the other issues that Randy mentioned. An equivalence rule seemed like the way to go, for the reasons Randy described. Originally, the idea was to use renaming semantics, so that LHS := Some_Func (@); could be treated as declare @ : T renames LHS; begin @ := Some_Func (@); end; But that didn't work if the LHS was something that was illegal to rename, such as Unconstrained_Variable.Discriminant_Dependent_Component So we instead said that the assignment is equivalent to declare procedure Foo (Param : in out T) is begin Param := Some_Func (T'(Param)); end; begin Foo (Lhs); end; The point is that while you cannot rename Unconstrained_Variable.Discriminant_Dependent_Component , you can pass it as an actual parameter. I don't recall the reason for the S'(P) qualification mentioned in the current wording. At the very least, Bob's suggestion would need to be augmented to state that the LHS name is evaluated before the RHS value. *************************************************************** From: Randy Brukardt Sent: Wednesday, March 6, 2019 5:57 PM ... > I don't recall the reason for the S'(P) qualification mentioned in the > current wording. I think it is a cutesy way to ensure that @ is a constant view. Since the parameter of the implicit subprogram is defined to be in out, it's a variable. I don't recall if there was a real issue with @ being a variable, or if we were just being pedantic. *************************************************************** From: Steve Baird Sent: Wednesday, March 6, 2019 6:07 PM Sounds right. *************************************************************** From: Bob Duff Sent: Wednesday, March 6, 2019 6:22 PM > I don't know how to handle this one. My first inclination is to ignore > it -- My intention for the RM review was that the editor would decide what to do -- agree or disagree with my suggestions. Perhaps in rare cases bring it up for discussion. But in any case, I'm not going to complain if you decide my suggestions are wrong. I certainly don't want to have endless arguments about these things. *************************************************************** From: Tucker Taft Sent: Wednesday, March 6, 2019 6:27 PM > I listed some of them in my original note: > > (1) What happens if the target is modified by evaluating the expression? > > Glob : Natural := 0; > > function Side_Effect return Natural is > begin > Glob := Glob + 1; > return 1; > end Side_Effect; > > Glob := @ + Side_Effect; > > Steve's wording says that Glob = 1 after this call, regardless of when > Side_Effect is evaluated. Bob's wording leaves it unspecified (because > it leaves *everything* unspecified). This would still seem to depend on whether Glob is passed by copy or by reference, which is implementation-defined for cases where Glob is something like a Big_Num. I agree for a by-copy type, the equivalence eliminates doubt in this case, though perhaps a couple of added words would resolve this, and we could in fact eliminate the by-ref vs. by-copy uncertainty should we so choose. In fact, if programmers use @ to be a short hand for simply writing the name again, they might be surprised the use of @ somehow eliminates an order dependence, and might not want to rely on that, but instead, would want to eliminate any possibility of such an order dependence. I certainly didn't think of "@" as eliminating such bizarro order dependencies, and I don't see it as a valuable feature of "@." If the semantics were that the order dependence still remained, I don't think anyone would complain. > (2) What happens if the target is discriminant-dependent and the > discriminant is changed? > > Glob.F := @ + Change_Glob; > > Steve's wording says this is erroneous (by the rule that says doing > this to a parameter is erroneous), Bob's wording says nothing. This is still erroneous without Steve's circumlocutions, per 3.7.2(4): "The execution of a construct is erroneous if the construct has a constituent that is a name denoting a subcomponent that depends on discriminants, and the value of any of these discriminants is changed by this execution between evaluating the name and the last use (within this execution) of the subcomponent denoted by the name. " > (3) How is the anti-order-dependence rules enforced? > > Targ := @.F + Func_with_In_Out (@.F.all); I presume you meant: "@.F.all + Func_With_In_Out(@.F.all);" unless you are doing "access type" arithmetic. I'm not sure I see the problem here, since @ is a name which denotes something (namely the same thing denoted by Targ), and the rules of 6.4.1(6.5-6.25) are all compile-time checks, so only compile-time properties matter. > Steve's wording gives an unequivocal answer, no idea for Bob's (since > it says nothing about anything). Not sure I agree, though it is helpful to lay out these specific issues, so we can discuss them as a group (for 10 minutes, say ;-) *************************************************************** From: John Barnes Sent: Thursday, March 7, 2019 1:44 AM Maybe this discussion reveals that @ was a bad idea after all. *************************************************************** From: Tucker Taft Sent: Thursday, March 7, 2019 2:45 AM > Maybe this discussion reveals that @ was a bad idea after all. Let's not go there! ;-) I would suggest that perhaps we adopt an object-renaming equivalence rather than the implicit procedure-call equivalence, and simply say the rule disallowing certain renamings of discriminant-dependent components (RM 8.5.1(5/3)) is relaxed in this equivalence. That seems pretty simple and matches the programmer's intuition better, I would argue. Note that the only reason for 8.5.1(5/3) is to reduce the likelihood of the erroneousness identified in 3.7.2(4), given that an object renaming could be quite long-lived. Given that "@" implies a much shorter extent for the (implicit) renaming, it is reasonable to suspend RM 8.5.1(5/3) and fall back on 3.7.2(4) to handle the possibility of side effects that change the value of a discriminant. I think a renaming equivalence would be much easier to understand, and more closely matches the programmer's intuition about what "@" means. It is also somewhat easier to implement, I would claim, since it doesn't depend on faking the semantics of parameter passing, with all of the by-copy vs. by-reference shenanigans. The renaming model is equivalent to a pure by-reference model, and will actually reduce the amount of implementation dependence. *************************************************************** From: Richard Wai Sent: Thursday, March 7, 2019 8:57 AM > Let's not go there! ;-) > > I would suggest that perhaps we adopt an object-renaming equivalence > rather than the implicit procedure-call equivalence, and simply say the rule > disallowing certain renamings of discriminant-dependent components (RM > 8.5.1(5/3)) is relaxed in this equivalence. That seems pretty simple > and matches the programmer's intuition better, I would argue. Hear, hear! > Glob : Natural := 0; > > function Side_Effect return Natural is > begin > Glob := Glob + 1; > return 1; > end Side_Effect; > Glob := @ + Side_Effect; In this example, I find it honestly inconceivable that the last statement would somehow not be _exactly_ equivalent to "Glob := Glob + Side_Effect;". That is the whole point of '@', and I cannot imagine a programmer who would not see it that way. It is a simple concept too, no need to make it do crazy things, it's ugly enough as it is! *************************************************************** From: Steve Baird Sent: Thursday, March 7, 2019 1:13 PM > I think a renaming equivalence would be much easier to understand, and more > closely matches the programmer's intuition about what "@" means. Agreed. The objection to that was that, without the rules relaxation you propose, it would cause certain reasonable uses of "@" to be illegal. I agree that the rules relaxation you propose is another good solution to the problem. And it makes it clear that the LHS is evaluated before we begin evaluation of the RHS. *************************************************************** From: Randy Brukardt Sent: Thursday, March 7, 2019 2:04 PM ... > That seems pretty simple > and matches the programmer's intuition better, I would argue. This seems like a reasonable approach to be, subject the next oddity raised by Steve. ;-) I presume that we would be renaming a qualified expression, so as to preserve the requirement that @ is a constant view. Could you propose some wording along these lines so I can write something up for the meeting? Preferably before the deadline, along with your RM review and the rewording of AI12-0282-1. :-) [As always, tell me if you're going to be a bit late, just so I'm not surprised by late submissions.] *************************************************************** From: Bob Duff Sent: Thursday, March 7, 2019 4:42 PM > And it makes it clear that the LHS is evaluated before we begin > evaluation of the RHS. I admit that things are not as simple as I implied in my note to Randy. I expected Randy to "take it or leave it", not start a long discussion. But I do think the renaming suggestion from Tucker is rather less arcane. *************************************************************** From: Randy Brukardt Sent: Thursday, March 7, 2019 9:20 PM > I admit that things are not as simple as I implied in my note to > Randy. I expected Randy to "take it or leave it", not start a long > discussion. I couldn't decide how to handle the comment. I had thought about it periodically for parts of three days, it was starting to drive me nuts, and concluded "if in doubt, ask the group" (especially better than obsessing over something not very important). > But I do think the renaming > suggestion from Tucker is rather less arcane. ...which is why I couldn't decide on what to do. You had a good point, just not a good replacement. And I'm trying not to write the *whole* standard by myself. *************************************************************** From: Tucker Taft Sent: Thursday, March 7, 2019 4:38 PM Here is an attempt to simplify the handling of target_name (aka "@"). I abandoned using an equivalence completely, because the dynamic semantics are so straightforward. ------- !subject Define target_name without recourse to an implicit procedure Replace RM 5.2.1 (5/5) with: Dynamic Semantics For the execution of an assignment_statement with one or more target_names appearing in its expression, the /variable_/name V of the assignment statement is evaluated first to determine the object denoted by V, and then the expression of the assignment_statement is evaluated with the evaluation of each target_name yielding a constant view of the object denoted by V. The remainder of the execution of the assignment_statement is as given in subclause 5.2. !discussion We are replacing the old equivalence which was based on an implicit procedure, with an explicit dynamic semantics defining what it means to evaluate a target_name. *************************************************************** From: Randy Brukardt Sent: Thursday, March 7, 2019 9:44 PM > Replace RM 5.2.1 (5/5) with: > > Dynamic Semantics > > For the execution of an assignment_statement with one or more > target_names appearing in its expression, the /variable_/name V of the > assignment statement is evaluated first to determine the object > denoted by V, and then the expression of the assignment_statement is > evaluated with the evaluation of each target_name yielding a constant > view of the object denoted by V. The remainder of the execution of > the assignment_statement is as given in subclause 5.2. There's at least one problem with this: the Name Resolution Rules are marked Redundant because "the nominal subtype is determined by the equivalence rules given below". It's weird and usually not the case that we define Static Semantics in Dynamic Semantic rules; that matters for properties like static accessibility and aliasedness. All of the cases I can think of are rare corner cases, though. (Yes, @'Access is possible, but not very likely.) I'm not sure about the anti-order-dependence rules, though, and particularly "known to denote the same object" and it's cousin. These depend on "statically denote", so one has to ask if '@' statically denotes anything. Maybe it doesn't matter enough, as those rules aren't expected to catch everything. I think we also want at least an AARM note about the erroneousness that can occur if the discriminant governing the target is changed; it's not at all obvious that such things can happen here. Although really that a problem with assignment statements as a whole -- they truly need such a note. (A cross-reference to 3.7.2(4) would be a big help, as it seems impossible to find that rule when it comes up in discussion. I would *never* have looked in 3.7.2, as the title of the clause says that it defines some attributes.) *************************************************************** From: Randy Brukardt Sent: Thursday, March 7, 2019 10:16 PM > I'm not sure about the anti-order-dependence rules, though, and > particularly "known to denote the same object" and it's cousin. These > depend on "statically denote", so one has to ask if '@' statically > denotes anything. > Maybe it doesn't matter enough, as those rules aren't expected to > catch everything. To expand on this a bit. The rule in question is 6.4.1(6.6/3): * both names statically denote the same stand-alone object or parameter; or This is clearly False for "@", at least as it stands: it doesn't statically denote anything (it can't do that in general in any case). Skimming the rest of it, it seems we were trying to avoid anything dynamic in the names, so just allowing identical names to match wouldn't work in every case (think function call), so this would need a complex definition to trigger. So my example from yesterday: Targ := @.F.all + Func_with_In_Out (@.F.all); is legal using @ as defined in your AI, but illegal as defined in with Steve's anonymous procedure (or even with a renames sans Legality, there's special rules for that case) and definitely if one wrote it without using @: Targ := Targ.F.all + Func_with_In_Out (Targ.F.all); One could argue that this isn't particularly important as the anti-order-dependence rules aren't intended to be complete anyway, but it seems bad that introducing a short-hand makes this particular case legal when it otherwise would not be as it was judged to be too non-portable to allow. *************************************************************** From: Tucker Taft Sent: Thursday, March 7, 2019 10:53 PM It seems all we need to do is add a bullet after 4.9(14), saying that if the target of an assignment statement statically denotes an object, then @ statically denotes the same object. That is, add after 4.9(15): * It is a target_name in an assignment_statement whose /variable_/name statically denotes the entity; *************************************************************** From: Tucker Taft Sent: Thursday, March 7, 2019 11:14 PM >> Replace RM 5.2.1 (5/5) with: >> >> Dynamic Semantics >> >> For the execution of an assignment_statement with one or more >> target_names appearing in its expression, the /variable_/name V of >> the assignment statement is evaluated first to determine the object >> denoted by V, and then the expression of the assignment_statement is >> evaluated with the evaluation of each target_name yielding a constant >> view of the object denoted by V. The remainder of the execution of >> the assignment_statement is as given in subclause 5.2. > > There's at least one problem with this: the Name Resolution Rules are > marked Redundant because "the nominal subtype is determined by the > equivalence rules given below". Oops. We should make the part about the nominal subtype normative. Hence, replace 5.2,1(3/5) with: [Redundant: If a target_name occurs in an assignment_statement A, the variable_name V of A is a complete context.] Each target_name in the assignment denotes a [Redundant: constant] view of V, having the nominal subtype of V. and modify 3.a/5: Proof: The complete context rule is formally given in 8.6. The constant view rule is formally given in 3.3[; the nominal subtype follows from the equivalence given below in Static Semantics]. ... > I think we also want at least an AARM note about the erroneousness > that can occur if the discriminant governing the target is changed; > it's not at all obvious that such things can happen here. Sure they could. Presuming the target of the assignment is a discriminant-dependent component, a call on a function somewhere in the RHS that assigns a value to the enclosing object with a different value of the discriminant will render the assignment erroneous. This is pretty much true whether or not there are target_names on the RHS, so I don't see it as a very important point for this section. The target_names aren't making it any better or any worse. Erroneous is erroneous! > Although really that a problem > with assignment statements as a whole -- they truly need such a note. > (A cross-reference to 3.7.2(4) would be a big help, as it seems > impossible to find that rule when it comes up in discussion. I would > *never* have looked in 3.7.2, as the title of the clause says that it > defines some attributes.) I could agree that assignment statements need such a note, but I don't think a target_name makes things worse. *************************************************************** From: Randy Brukardt Sent: Friday, March 8, 2019 12:04 AM ... > > I think we also want at least an AARM note about the erroneousness > > that can occur if the discriminant governing the target is changed; > > it's not at all obvious that such things can happen here. > > Sure they could. Certainly, I meant "not obvious to the causal reader". It's not obvious to me... > Presuming the target of the assignment is a discriminant-dependent > component, a call on a function somewhere in the RHS that assigns a > value to the enclosing object with a different value of the > discriminant will render the assignment erroneous. This is pretty > much true whether or not there are target_names on the RHS, so I don't > see it as a very important point for this section. But the only reason *I* thought of this is because Steve pointed it out back when target names were originally defined. Otherwise, I would never have considered such a possibility, and since the rule involving is it buried in a bizarre place, I wouldn't have been able to figure it out. (How the heck did you find that rule yesterday? I've looked for it for hours in the past without finding it.) > The target_names aren't making it any better or any worse. Actually, target names do make it worse (maybe not significantly). When you have: T.F := T.F + Mods_T; there are two names here, and the second T.F is evaluated and the value is used only once and (probably) used immediately. The time window for execution to go erroneous is very short (and given that parallel execution is not allowed for expression evaluation), nonexistent for this expression. If Mods_T was called before T.F was evaluated, the evaluation of T.F will raise an exception. In this case, there is no erroneous execution. Of course, the other order is erroneous (because of the assignment into T.F). This is one of the reasons Janus/Ada tries to call functions first in expressions, regardless of how they're written (it also decreases register pressure). OTOH: T.F := @ + Mods_T; There is a lot longer time between the time that @ is evaluated and the value used, so there is a substantially greater time for the execution to become erroneous -- the entire time that the expression is being evaluated. Using @, the expression will be erroneous regardless of the order, and a friendly compiler can't help this. > Erroneous is erroneous! As I show above, not necessarily. :-) Maybe not a significant difference, but the ordering in Janus/Ada has definitely helped debugging by preventing this sort of erroneousness. > > Although really that a problem > > with assignment statements as a whole -- they truly need such a note. > > (A cross-reference to 3.7.2(4) would be a big help, as it seems > > impossible to find that rule when it comes up in discussion. I would > > *never* have looked in 3.7.2, as the title of the clause says that > > it defines some attributes.) > > I could agree that assignment statements need such a note, but I don't > think a target_name makes things worse. Well, I wrote the note when I created the AI a few hours ago. We can decide on Monday what to do with it. *************************************************************** From: Tucker Taft Sent: Friday, March 8, 2019 8:18 AM > ... > >> Erroneous is erroneous! > > As I show above, not necessarily. :-) Maybe not a significant > difference, but the ordering in Janus/Ada has definitely helped > debugging by preventing this sort of erroneousness. All good points. >>> Although really that a problem >>> with assignment statements as a whole -- they truly need such a note. >>> (A cross-reference to 3.7.2(4) would be a big help, as it seems >>> impossible to find that rule when it comes up in discussion. I would >>> *never* have looked in 3.7.2, as the title of the clause says that >>> it defines some attributes.) >> >> I could agree that assignment statements need such a note, but I >> don't think a target_name makes things worse. > > Well, I wrote the note when I created the AI a few hours ago. We can > decide on Monday what to do with it. Sounds good. ***************************************************************