Version 1.4 of ai12s/ai12-0125-3.txt

Unformatted version of ai12s/ai12-0125-3.txt version 1.4
Other versions for file ai12s/ai12-0125-3.txt

!standard 5.2.1(0)          16-01-08 AI12-0125-3/02
!standard 4.1(2/3)
!standard 8.6(9/4)
!class Amendment 15-10-13
!status work item 15-10-13
!status received 15-09-22
!priority Low
!difficulty Medium
!subject Add @ as a shorthand for the LHS of an assignment
!summary
Define @, which can be used in the right-hand side of an assignment statement as a shorthand for the name of the left-hand side.
!problem
Incrementing, decrementing, scaling, etc., are all somewhat painful in Ada, particularly if the object being updated has a long name, or involves any sort of dynamic addressing:
My_Package.My_Array(I).Field := My_Package.My_Array(I).Field + 1;
Some sort of short-hand would be welcome, as it would ease both readability and writability, while reducing the possibility of error, such as unintended multiple evaluations of expressions in the name, or mismatching array indices.
!proposal
We define a new symbol, @, the target name which represents a constant view of the left-hand side of an assignment.
!wording
Add after 3.3(21.1/3): [Editor's note: This is the list of items that are defined to be constant. Since that list is defined to be exclusive, we have to include target_name here.]
* a target_name of an assignment_statement when used in the expression of the assignment (see 5.2.1);
[Editor's note: The "when used in the expression of the assignment" isn't strictly necessary, as that is the only place a target_name is allowed. But this is a forward reference and a causal reader might interpret this as applying to the variable_name of the assignment -- which it does not.]
Add target_name to the syntax of Name in 4.1(2/3).
[Editor's note: We add a new syntax nonterminal because all of the other kinds of name are defined that way, rather than by reference to other subclauses as is done for a primary. We try to be consistent within a clause, even if the Standard is not consistent for similar constructs.]
Add a new subclause:
5.2.1 Target name (@) shorthand
@, known as the target name of an assignment statement, provides a shorthand to avoid repetition of potentially long names in assignment statements.
Syntax
Target_Name ::= @
Name Resolution Rules
Redundant[If a target_name T occurs in an assignment_statement A, the variable_name V of A is a complete context.] T is a constant view of V, having the nominal subtype of V.
AARM The Proof: The complete context rule is formally given in 8.6.
Legality Rules
A target_name shall only appear in the expression of an assignment_statement.
Static Semantics
If a target_name with nominal subtype S appears in the expression of an assignment statement A, then A is equivalent to a local anonymous procedure having an in out parameter P of subtype S, with a body being S with the variable_name being replaced by P, and any target_names being replaced by the qualified expression S'(P); followed by a call on the anonymous procedure with the actual parameter being the variable_name of S.
[Editor's note: We use a qualified expression here to ensure the replacement has the semantics of a constant view. I would have preferred to avoid that (a target_name is a constant view by rule), but just using P here is misleading, especially if someone is doing expression analysis after this expansion. We could probably drop the explicit definition of @ as a constant view, since this expansion would have that effect anyway, but it seems valuable to emphasize that to readers.]
AARM Reason: This equivalence defines all of the Dynamic Semantics for these assignment statements. We use the parameter to bind the variable_name; it is evaluated only once.
AARM Discussion:
For example, the expression
My_Array(I) := @*2 + @/2;
would be equivalent to
declare procedure [Anon] ([Target] : in out [Target_Subtype]) is begin [Target] := [Target_Subtype]'([Target])*2 + [Target_Subtype]'([Target])/2; end [Anon];
begin [Anon] ([Target] => My_Array(I)); end;
where all of the identifiers in square brackets are anonynous placeholders. End AARM Discussion.
Add after 8.6(9/4):
* The *variable_*name of an assignment_statement *A*, if the expression of A contains one or more target_names.
!examples
X := @ + 1; -- A shorthand for X := X + 1;
A(I) := Integer'Max (@, 10); -- Equivalent to: -- declare -- procedure Anon (Target : in out Integer) is -- begin -- Target := Integer'Max (Integer'(Target), 10); -- end Anon; -- begin -- Anon (A(I)); -- end;
!discussion
The occurrence of a target_name (@) in an assignment makes the /variable_/name (the left-hand side of the assignment) a complete context. This avoids complicating resolution unnecessarily; otherwise it would be possible for the LHS to be overloaded in such a way that the uses of @ determine which possibility is correct. This is especially complicated as @ has to resolve the same as the LHS, whereas a simple textual substitution would not have that property. We avoid the complication by legislating it away.
This is potentially a maintenance hazard, as introducing @ into an assignment_statement potentially could make it illegal. However, since stand-alone objects and parameters cannot be overloaded, this will rarely make a difference in practice (there is rarely more than one interpretation of the LHS of an assignment).
The expansion in terms of an anonymous procedure preserves the possibility of erroneous execution in obscure cases:
type Mutable (D : Boolean := True) is record case D is when True => I : Integer; when False => F : Float; end case; end record;
Obj : Mutable;
function Fooey return Integer is Temp : Integer := Obj.I; begin Obj := (D => False, F => Float(Temp)); return Temp; end Fooey;
Obj.I := @ + Fooey; -- (1) Obj.I := Obj.I + Fooey; -- (2)
In these assignments, the I component doesn't exist when it is written. Ada doesn't try to prevent that, both (1) and (2) are erroneous.
We considered using a renames formulation instead:
Obj.I := @ + 1;
being the same as:
declare <Target> : renames Integer := Obj.I; -- (3) begin <Target> := <Target> + 1; end;
However, this doesn't work in this case, as the renames of a discriminant dependent-component (like (3)) is illegal. Since the update to the I component is the sort of use this feature is constructed for, making it illegal seems too restrictive. (And this is not a new kind of erroneous execution, as demonstrated previously).
Note that the subprogram call introduced by this formulation could introduce an extra possibility of a failing subtype check, but this can happen only if the value of the variable_name is invalid or a predicate has a side-effect. In these cases, reading the variable_name isn't going to be safe anyway, so the effect is mainly to make a latent error more visible.
The target_name is a constant view of the LHS of the assignment. We do this mainly so that the use of @ does not trigger the Taft anti-aliasing rules (6.4.1). A side-effect is that the target object cannot be modified directly via @, preventing problems. We accomplish this by defining the target_name to expand to a qualified_expression; that expression could introduce an extra exception, but only if a predicate has a side-effect (the subtype conversion was already done by the parameter passing, this is just a repeat).
This proposal is better than AI12-0125-2, as
(1) It is more flexible; it can be used in function calls other than operators
(as shown by the 'Max example above).
(2) There is a positive indication that this notation is being used (the
addition of an @ as opposed to deleting an '=');
(3) It doesn't (directly) depend on visibility of anything; it's always
available unless the LHS of the assignment is overloaded.
It is different than the proposal of AI12-0125-2: (whether these are advantages or disadvantages are in the eye of the beholder -- the author finds these to be advantages)
(1) Only one new lexical symbol is needed, rather than many. (2) It doesn't have an "obvious" extension to a user-defined version, which
avoids a nasty slippery slope.
(3) It doesn't look like we're out of ideas by stealing groddy parts of other
languages.
This proposal is the same as the proposal AI12-0125-2 in the following ways:
(1) The semantics is described in terms of an anonymous procedure. (2) The left-hand side of the assignment is treated as a complete context,
meaning that in rare cases, introducing @ into an assignment (or using :+) would make the assignment illegal.
These should be considered issues with solving the problem as opposed to negatives against a particular proposal.
(3) Both are only one character different from very different expressions:
Obj:=@+1; vs. Obj:=+1; -- This proposal Obj:+1; vs. Obj:=+1; -- The alternative AI12-0125-2
Of course, writing without whitespace is discouraged in Ada, but these are legal expressions regardless of common practice. This problem could be eliminated for this proposal by using more than one character for the target name (as the original proposal <<>> did).
!ASIS
** TBD **
!ACATS Tests
ACATS B and C-Tests would be needed.
!appendix

****************************************************************

Questions? Ask the ACAA Technical Agent