Annotated Ada Reference ManualLegal Information
Table of Contents   Index   References   Search   Previous   Next 

 5.2 Assignment Statements

[An assignment_statement replaces the current value of a variable with the result of evaluating an expression.] 


assignment_statement ::= 
   variable_name := expression;
The execution of an assignment_statement includes the evaluation of the expression and the assignment of the value of the expression into the target. {assignment operation [distributed]} {assign: See assignment operation} [An assignment operation (as opposed to an assignment_statement) is performed in other contexts as well, including object initialization and by-copy parameter passing.] {target (of an assignment operation)} {target (of an assignment_statement)} The target of an assignment operation is the view of the object to which a value is being assigned; the target of an assignment_statement is the variable denoted by the variable_name.
Discussion: Don't confuse this notion of the “target” of an assignment with the notion of the “target object” of an entry call or requeue.
Don't confuse the term “assignment operation” with the assignment_statement. The assignment operation is just one part of the execution of an assignment_statement. The assignment operation is also a part of the execution of various other constructs; see 7.6.1, “Completion and Finalization” for a complete list. Note that when we say, “such-and-such is assigned to so-and-so”, we mean that the assignment operation is being applied, and that so-and-so is the target of the assignment operation. 

Name Resolution Rules

{AI95-00287-01} {expected type (assignment_statement variable_name) [partial]} The variable_name of an assignment_statement is expected to be of any nonlimited type. {expected type (assignment_statement expression) [partial]} The expected type for the expression is the type of the target. 
Implementation Note: An assignment_statement as a whole is a "complete context," so if the variable_name of an assignment_statement is overloaded, the expression can be used to help disambiguate it. For example: 
  type P1 is access R1;
  type P2 is access R2;
  function F return P1;
  function F return P2;
  X : R1;
  F.all := X;  -- Right hand side helps resolve left hand side

Legality Rules

{AI95-00287-01} The target [denoted by the variable_name] shall be a variable of a nonlimited type.
If the target is of a tagged class-wide type T'Class, then the expression shall either be dynamically tagged, or of type T and tag-indeterminate (see 3.9.2).
Reason: This is consistent with the general rule that a single dispatching operation shall not have both dynamically tagged and statically tagged operands. Note that for an object initialization (as opposed to the assignment_statement), a statically tagged initialization expression is permitted, since there is no chance for confusion (or Tag_Check failure). Also, in an object initialization, tag-indeterminate expressions of any type covered by T'Class would be allowed, but with an assignment_statement, that might not work if the tag of the target was for a type that didn't have one of the dispatching operations in the tag-indeterminate expression.

Dynamic Semantics

{execution (assignment_statement) [partial]} For the execution of an assignment_statement, the variable_name and the expression are first evaluated in an arbitrary order. 
Ramification: Other rules of the language may require that the bounds of the variable be determined prior to evaluating the expression, but that does not necessarily require evaluation of the variable_name, as pointed out by the ACID. 
When the type of the target is class-wide: 
Ramification: See 3.9.2, “Dispatching Operations of Tagged Types”.
The value of the expression is converted to the subtype of the target. [The conversion might raise an exception (see 4.6).] {implicit subtype conversion (assignment_statement) [partial]}
Ramification: 4.6, “Type Conversions” defines what actions and checks are associated with subtype conversion. For non-array subtypes, it is just a constraint check presuming the types match. For array subtypes, it checks the lengths and slides if the target is constrained. “Sliding” means the array doesn't have to have the same bounds, so long as it is the same length. 
In cases involving controlled types, the target is finalized, and an anonymous object might be used as an intermediate in the assignment, as described in 7.6.1, “Completion and Finalization”. {assignment operation} {assignment operation (during execution of an assignment_statement)} In any case, the converted value of the expression is then assigned to the target, which consists of the following two steps: 
To be honest: 7.6.1 actually says that finalization happens always, but unless controlled types are involved, this finalization during an assignment_statement does nothing. 
Ramification: If any parts of the object are controlled, abort is deferred during the assignment operation itself, but not during the rest of the execution of an assignment_statement.
2  The tag of an object never changes; in particular, an assignment_statement does not change the tag of the target.
This paragraph was deleted.3  {AI95-00363-01} The values of the discriminants of an object designated by an access value cannot be changed (not even by assigning a complete value to the object itself) since such objects are always constrained; however, subcomponents of such objects may be unconstrained. 
Ramification: The implicit subtype conversion described above for assignment_statements is performed only for the value of the right-hand side expression as a whole; it is not performed for subcomponents of the value.
The determination of the type of the variable of an assignment_statement may require consideration of the expression if the variable name can be interpreted as the name of a variable designated by the access value returned by a function call, and similarly, as a component or slice of such a variable (see 8.6, “The Context of Overload Resolution”).


Examples of assignment statements: 
Value := Max_Value - 1;
Shade := Blue;
Next_Frame(F)(M, N) := 2.5;        --  see 4.1.1
U := Dot_Product(V, W);            --  see 6.3
Writer := (Status => Open, Unit => Printer, Line_Count => 60);  -- see 3.8.1
Next_Car.all := (72074, null);    --  see 3.10.1
Examples involving scalar subtype conversions: 
I, J : Integer range 1 .. 10 := 5;
K    : Integer range 1 .. 20 := 15;
I := J;  --  identical ranges
K := J;  --  compatible ranges
J := K;  --  will raise Constraint_Error if K > 10
Examples involving array subtype conversions: 
A : String(1 .. 31);
B : String(3 .. 33);
A := B;  --  same number of components
A(1 .. 9)  := "tar sauce";
A(4 .. 12) := A(1 .. 9);  --  A(1 .. 12) = "tartar sauce"
4  Notes on the examples: Assignment_statements are allowed even in the case of overlapping slices of the same array, because the variable_name and expression are both evaluated before copying the value into the variable. In the above example, an implementation yielding A(1 .. 12) = "tartartartar" would be incorrect. 

Extensions to Ada 83

{extensions to Ada 83} We now allow user-defined finalization and value adjustment actions as part of assignment_statements (see 7.6, “User-Defined Assignment and Finalization”).

Wording Changes from Ada 83

The special case of array assignment is subsumed by the concept of a subtype conversion, which is applied for all kinds of types, not just arrays. For arrays it provides “sliding”. For numeric types it provides conversion of a value of a universal type to the specific type of the target. For other types, it generally has no run-time effect, other than a constraint check.
We now cover in a general way in 3.7.2 the erroneous execution possible due to changing the value of a discriminant when the variable in an assignment_statement is a subcomponent that depends on discriminants. 

Incompatibilities With Ada 95

{AI95-00287-01} {incompatibilities with Ada 95} The change of the limited check from a resolution rule to a legality rule is not quite upward compatible. For example
type AccNonLim is access NonLim;
function Foo (Arg : in Integer) return AccNonLim;
type AccLim is access Lim;
function Foo (Arg : in Integer) return AccLim;
Foo(2).all := Foo(1).all;
where NonLim is a nonlimited type and Lim is a limited type. The assignment is legal in Ada 95 (only the first Foo would be considered), and is ambiguous in Ada 2005. We made the change because we want limited types to be as similar to nonlimited types as possible. Limited expressions are now allowed in all other contexts (with a similar incompatibility), and it would be odd if assignments had different resolution rules (which would eliminate ambiguities in some cases). Moreover, examples like this one are rare, as they depend on assigning into overloaded function calls. 

Table of Contents   Index   References   Search   Previous   Next 
Ada-Europe Sponsored by Ada-Europe