7.5. Assignment

The most common use of the result of an expression is to give a value to a variable. This is done with an assignment statement. For example:

RUG = BROWN + 2.34 / TINT

The forms of intrinsic assignment, defined assignment, and masked array assignment are the same, and they are defined as follows:

Table 7-26.

 

assignment_stmt

is

variable = expr

Assignment establishes a value for the variable on the left of the assignment symbol in an assignment statement. Execution of the assignment statement causes the expression to be evaluated (by performing the computation indicated), and then the value of the expression is assigned to the variable. If the variable has subscripts, section subscripts, or a substring range, the execution of the assignment statement must behave as if they were evaluated before any part of the value is assigned.

There are four forms of the assignment statement: intrinsic assignment, defined assignment, pointer assignment, and masked array assignment.

An assignment statement is a defined assignment if the following conditions are true:

An assignment statement is a masked array assignment if it appears in a WHERE construct, WHERE statement, FORALL statement, or FORALL construct; otherwise, it is an intrinsic or defined assignment.

The form of the pointer assignment statement is similar to the assignment statement except that the assignment operator is => instead of =.

The rules and restrictions for each of these forms of assignment are different and are described in the sections below for each form of assignment.

The following examples show the forms of assignment:

Expression 

Meaning

X = X + 1.0 

Intrinsic assignment for reals

CHAR(1:4) = "A123" 

Intrinsic assignment for characters

STUDENT = B_JONES 

Intrinsic assignment for structures if STUDENT and B_JONES are of the same derived type

STRING = "Brown" 

Defined assignment for structure if STRING is of derived type and an interface exists that defines the operator = for the types STRING and character

X=Y 

Defined elemental assignment in which X and Y are both arrays of derived type. In addition, an interface exists that defines the operator = for the type and shape of the array, and the specific is elemental.

WHERE (Z /= 0.0), A = B / Z, END WHERE 

Masked array assignment

PTR => X 

Pointer assignment

7.5.1. Intrinsic Assignment

Intrinsic assignment can be used to assign a value to a nonpointer variable of any type or to the target associated with a pointer variable. The assignment statement defines or redefines the value of the variable or the target, as appropriate. The value is determined by the evaluation of the expression on the right side of the equal sign.

The types and kind parameters of the variable and expression in an intrinsic assignment statement must be of the types given in Table 7-27.

Table 7-27. Types Of The Variable And Expression In An Intrinsic Assignment

Type of the variable

Type of the expression

Integer

Integer, real, complex, Boolean, Cray pointer

Real

Integer, real, complex, Boolean

Complex

Integer, real, complex

Character

Character

Logical

Logical

Cray pointer

Cray pointer, integer, Boolean

Derived type

Same derived type as the variable

Note: The Fortran standard does not define Boolean or Cray pointer types.

If the variable is an array, the expression must either be a scalar or an array of the same shape as the variable. If the variable is a scalar, the expression must be a scalar. The shape of the variable can be specified in specification statements if it is an explicit-shape array. The shape of the variable can be determined by the section subscripts in the variable, by an actual argument if it is a assumed-shape array, or by an ALLOCATE statement or a pointer assignment statement if it is a deferred-shape array. It must not be an assumed-size array unless there is a vector subscript, a scalar subscript, or a section subscript containing an upper bound in the last dimension of the array. The shape of the expression is determined by the shape of the operands, the operators in the expression, and the functions referenced in the expression. A complete description of the shape of an expression appears in Section 7.2.8.3.

If the variable is a pointer, it must be associated with a target; the assignment statement assigns the value of the expression to the target of the pointer. The pointer can be associated with a target that is an array; the pointer determines the rank of the array, but the extents in each dimension are that of the target.

The evaluation of the expression on the right-hand side of the equal sign, including subscript and section subscript expressions that are part of the expression and part of the variable, must be performed before any portion of the assignment is performed. Consider the following statement:

I(I(1:N:2)) = I(1:M) + 3

In the preceding statement, the expression to the right of the equal sign (the I(1:M) + 3) and the subscript expression (the I(1:N:2)) must be evaluated before any assignment to destination variable I, which is an array.

Before the assignment begins, any necessary type conversions are completed if the variable has a different numeric type or type parameter from the expression. The conversion is the same as that performed by the conversion intrinsic functions INT(3i), REAL(3i), CMPLX(3i), and LOGICAL(3i), as specified in Table 7-28. If the expression is of type Boolean or is a BOZ constant, no conversion is done.

Note: The Fortran standard does not specify type Boolean or BOZ constants in assignment statements.

Table 7-28. Conversion Performed On An Expression Before Assignment

Type of the variable

Value assigned

Integer

INT (expr, KIND (variable))

Real

REAL (expr, KIND (variable))

Complex

CMPLX (expr, KIND (variable))

Logical

LOGICAL (expr, KIND (variable))

An expression can use parts of the variable that appear on the left side of an assignment statement. For example, in evaluating a character string expression on the right-hand side of an assignment, the values in the variable on the left-hand side can be used, as in the following example:

DATE(2:5) = DATE(1:4)

If the variable and expression are of character type with different lengths, the assignment occurs as follows:

The evaluation of expressions in the variable on the left-hand side, such as subscript expressions, has no effect on, nor is affected by, the evaluation of the expression on the right-hand side, which is evaluated completely first. As usual, this requirement that the expression on the right be evaluated first is specifying the semantics of the statement and does not imply that an implementation must perform the computation in this way if there is an equivalent order that computes the same result.

When a scalar is assigned to an array, the assignment behaves as if the scalar is broadcast to an array of the shape of the variable; it is then in shape conformance with the variable. In the following example, all ten elements of the array A are assigned the value 1.0:

REAL A(10)
A = 1.0

Array assignment is element-by-element, but the order is not specified. Assume that A and B are real arrays of size 10, and the whole array assignment is as follows:

A = B

The first element of B would be assigned to the first element of A, the second element of B would be assigned to the second element of A, and this would continue element-by-element for 10 elements. The assignment of elements, however, may be performed in any order.

For derived-type- or type-alias intrinsic assignment, the types of the variable and the expression must be the same. Derived-type or type-alias intrinsic assignment is performed component-by-component following the above rules, except when a component is a pointer. For pointer components, pointer assignment between corresponding components is used.

For intrinsic assignment of objects that are of a derived type that contain an allocatable component, the allocatable component of the variable on the left-hand side receives the allocation status and, if allocated, the shape and value of the corresponding component of the expression. This occurs as if the following steps are carried out:

7.5.2. Defined Assignment

A defined assignment is an assignment operation provided by a subroutine with an assignment interface ASSIGNMENT (=). A defined assignment operation will be used when the variable and expression in the assignment statement are of the types below, provided the assignment interface and subroutine are accessible:

For example, a defined assignment may apply when an integer object is to be assigned to a logical variable, provided a subroutine with a generic assignment interface is accessible. Assignment thus can be extended to types other than the intrinsic types or can replace the intrinsic assignment operation for derived types, if the programmer defines the rules for this assignment in a subroutine. For more information on the assignment interface, see the Fortran Language Reference Manual, Volume 2.

An assignment operation is declared by using a subroutine with two dummy arguments.

The dummy arguments to the subroutine represent the variable and the expression, in that order.

There must be an interface block for the subroutine with the generic specifier of the form ASSIGNMENT(=).

The types and kind type parameters of the variable and expression in the assignment statement must be the same as those of the dummy arguments.

The rank of the variable and the expression in the assignment must match the ranks of the corresponding dummy arguments.

One of the following conditions must be true:

Example:

INTERFACE  ASSIGNMENT (=)

   SUBROUTINE  RATIONAL_TO_REAL(L, R)
      USE  RATIONAL_MODULE
      TYPE(RATIONAL), INTENT(IN)   :: R
      REAL, INTENT(OUT)            :: L
   END SUBROUTINE  RATIONAL_TO_REAL
   SUBROUTINE  REAL_TO_RATIONAL(L, R)
      USE  RATIONAL_MODULE
      REAL, INTENT(IN)              :: R
      TYPE(RATIONAL), INTENT(OUT)   :: L
   END SUBROUTINE  REAL_TO_RATIONAL

END INTERFACE

The preceding interface block specifies two defined assignments for two assignment operations in terms of two external subroutines, one for assignment of objects of type RATIONAL to objects of type real, and the other for assignment of objects of type real to objects of type RATIONAL. With this interface block, the following assignment statements are defined:

REAL  R_VALUE
TYPE(RATIONAL)  RAT_VALUE

R_VALUE = RATIONAL(1, 2)
RAT_VALUE = 3.7

The effect of the defined assignment on variables in the program is determined by the referenced subroutine.

7.5.3. Pointer Assignment

A pointer is a variable with the POINTER attribute that points to another object. The term pointer association is used for the concept of "pointing to" and the term target is used for the object associated with a pointer.

A pointer assignment associates a pointer with a target. If the target is disassociated or undefined, the pointer becomes disassociated or undefined according to the status of the target.

Once a pointer assignment has been executed, the association status of the pointer remains unchanged until one of the following events occurs:

The pointer assignment statement is defined as follows:

Table 7-29.

 

pointer_assignment_stmt

is

pointer_object => target

 

pointer_object

is

variable_name

 

 

or

structure_component

 

target

is

variable

 

 

or

expr

If the pointer object is a variable name, the name must have the POINTER attribute. If the pointer object is a structure component, the component must have the POINTER attribute.

The form of the expression permitted as a target is severely limited.

If the target is a variable, then it must have one of the following characteristics:

The type, kind type parameters (including length, if character), and rank of the target must be the same as the pointer object.

If the variable on the right of => has the TARGET attribute, the pointer object on the left of => becomes associated with this target.

If the variable on the right of => has the POINTER attribute and is associated, the pointer object on the left of => points to the same data that the target points to after the pointer assignment statement is executed.

If the variable on the right of => has the POINTER attribute and is disassociated, or if it is a reference to the NULL(3i) intrinsic, the pointer object on the left of => becomes disassociated.

If the variable on the right of => has the POINTER attribute and has an undefined association status, the association status of the pointer object on the left of => becomes undefined.

A pointer assignment statement terminates any previous association for that pointer and creates a new association.

If the pointer object is a deferred-shape array, the pointer assignment statement establishes the extents for each dimension of the array, unless the target is a disassociated or undefined pointer. Except for the case of a disassociated or undefined pointer, the extents are those of the target. For example, if the following statements have been processed, the extents of P1 are those of T, namely 11 and 20, but those of P2 are 1 and 10, because T(:) has a section subscript list:

INTEGER, TARGET :: T(11:20)
INTEGER, POINTER :: P1(:), P2(:)
P1 => T
P2 => T(:)

The target must not be a variable that is an assumed-size array. If it is an array section of an assumed-size array, the upper bound for the last dimension must be specified.

If the target is an array section, it must not have a vector subscript.

If the target is an expression, it must deliver a pointer result. This implies that the expression must be a user-defined function reference or defined operation that returns a pointer (there are no intrinsic operations or functions that return results with the POINTER attribute). This also implies that a pointer can never point at a constant because constants cannot have the TARGET attribute.

If the target of a pointer cannot be referenced or defined, the pointer must not be referenced or defined.

If a structure has a component with the POINTER attribute and the structure is assigned a value using an intrinsic derived-type assignment, pointer assignment is used for each component with the POINTER attribute. Also, defined assignment may cause pointer assignment between some components of a structure.

Note that when a pointer appears on the right side of => in a pointer assignment, the pointer on the left side of => is defined or redefined to be associated with the target on the right side of the =>; neither the pointer on the right nor its target are changed in any way.

General examples:

MONTH => DAYS(1:30)
PTR => X(:, 5)
NUMBER => JONES % SOCSEC

Example 1: In this example, the target is another pointer:

REAL, POINTER :: PTR, P
REAL, TARGET :: A
REAL  B
A = 1.0
P => A
PTR => P
B = PTR + 2.0

The previous program segment defines A with the value 1.0, associates P with A; then PTR is associated with A as well (through P). The value assigned to B in the regular assignment statement is 3.0, because the reference to PTR in the expression yields the value of the target A which is the value 1.0.

Example 2: In this example, the target is an expression:

INTERFACE
   FUNCTION POINTER_FCN(X)
      REAL  X
      REAL, POINTER :: POINTER_FCN
   END FUNCTION
END INTERFACE

REAL, POINTER :: P
REAL  A

P => POINTER_FCN(A)

In this example, the function POINTER_FCN takes a real argument and returns a pointer to a real target. After execution of the pointer assignment statement, the pointer P points to this real target.

Pointers can become associated by using the ALLOCATE statement instead of a pointer assignment statement. Pointers can become disassociated by using the DEALLOCATE or NULLIFY statements, as well as with the pointer assignment statement.

A pointer can be used in an expression (see Section 7.3.1.4, for the details). Briefly, any reference to a pointer in an expression, other than in a pointer assignment statement, or in certain procedure references, yields the value of the target associated with the pointer. When a pointer appears as an actual argument corresponding to a dummy argument that has the POINTER attribute, the reference is to the pointer and not the value. Note that a procedure must have an explicit interface if it has a dummy argument with the POINTER attribute. For information on explicit interfaces, see the Fortran Language Reference Manual, Volume 2.

7.5.4. Masked Array Assignment

Sometimes it is desirable to assign only certain elements of one array to another array. To invert the elements of an array element-by-element, for example, you have to avoid elements that are 0. The masked array assignment is ideal for such selective assignment, as the following example using a WHERE construct illustrates:

REAL  A(10,10)
  ...
WHERE (A /= 0.0)
    RECIP_A = 1.0 / A   ! Assign only where the
                        !    elements are nonzero
ELSEWHERE
    RECIP_A = 1.0       ! Use the value 1.0 for
                        !    the zero elements
END WHERE

The first array assignment statement is executed for only those elements where the mask A /= 0.0 is true. Next, the second assignment statement (after the ELSEWHERE statement) is executed for only those elements where the same mask is false. If the values of RECIP_A where A is 0 are never used, this example can be simply written by using the WHERE statement, rather than the WHERE construct, as follows:

WHERE (A /= 0.0) RECIP_A = 1.0 / A

A masked array assignment is an intrinsic assignment statement in a WHERE block, an ELSEWHERE block, or a WHERE statement for which the variable being assigned is an array. The WHERE statement and WHERE construct appear to have the characteristics of a control statement or construct such as the IF statement and IF construct. But there is a major difference: every assignment statement in a WHERE construct is executed, whereas at most one block in the IF construct is executed. Similarly, the assignment statement following a WHERE statement is always executed. For this reason, WHERE statements and constructs are discussed here under assignment rather than under control constructs.

In a masked array assignment, the assignment is made to certain elements of an array based on the value of a logical array expression serving as a mask for picking out the array elements. The logical array expression acts as an array-valued condition on the elemental intrinsic operations, functions, and assignment for each array assignment statement in the WHERE statement or WHERE construct.

As in an intrinsic array assignment, a pointer to an array can be used as the variable, and a pointer to a scalar or an array can be used as a primary in the expression. If the target of the pointer is an array, the target array is masked in the same manner as a nonpointer array used in a masked array assignment.

7.5.4.1. WHERE Statement and Construct

The WHERE construct is defined as follows:

Table 7-30.

 

where_stmt

is

WHERE (mask_expr) where_assignment_stmt

 

where_construct

is

where_construct_stmt
     [ where_body_construct ] ... 
    [ masked_elsewhere_stmt 
     [ where_body_construct ] ...  ] ...
   [ elsewhere_stmt
     [ where_body_construct ] ... ]
  end_where_stmt

 

where_construct_stmt

is

[ where_construct_name: ] WHERE ( mask_expr)

 

where_body_construct

is

where_assignment_stmt

 

 

or

where_stmt

 

 

or

where_construct

 

where_assignment_stmt

is

assignment_stmt

 

mask_expr

is

logical_expr

 

masked_elsewhere_stmt

is

ELSEWHERE (mask_expr) [  where_construct_name ]

 

elsewhere_stmt

is

ELSEWHERE [ where_construct_name ]

 

end_where_stmt

is

END WHERE [ where_construct_name ]

The definition of the WHERE construct can be simplified to the following general format:

WHERE (condition_1) ! STATEMENT_1
   ...
   ELSEWHERE (condition_2)    ! STATEMENT_2
   ...
   ELSEWHERE           ! STATEMENT_3
   ...
   END WHERE

The following information applies to the preceding general format:

  • Following execution of STATEMENT_1, the control mask has the value condition_1 and the pending control mask has the value .NOT.condition_1.

  • Following execution of STATEMENT_2, the control mask has the value (.NOT.condition_1).AND.condition_2 and the pending control mask has the value (.NOT.condition_1).AND.(.NOT.condition_2).

  • Following execution of STATEMENT_3, the control mask has the value (.NOT.condition_1).AND.(.NOT.condition_2).

  • The false condition values are propagated through the execution of the masked ELSEWHERE statement.

If an array constructor appears in a where_assignment_stmt or in a mask_expr, the array constructor is evaluated without any masked control. After that, the where_assignment_stmt is executed or the mask_expr is evaluated.

When a where_assignment_stmt is executed, the values of expr that correspond to true values of the control mask are assigned to the corresponding elements of variable.

A statement that is part of a where_body_construct must not be a branch target statement. The value of the control mask is established by the execution of a WHERE statement, a WHERE construct statement, an ELSEWHERE statement, a masked ELSEWHERE statement, or an ENDWHERE statement. Subsequent changes to the value of entities in a mask_expr have no effect on the value of the control mask. The execution of a function reference in the mask expression of a WHERE statement is permitted to affect entities in the assignment statement. Execution of an END WHERE has no effect.

If the where_construct_stmt has a where_construct_name, then the corresponding end_where_stmt must specify the same name. If the construct also has an elsewhere_stmt or masked_ elsewhere_stmt, it must have the same where_construct_name. If no where_construct_name is specified for the where_construct, then the end_where_stmt and any elsewhere_stmt or masked_elsewhere_stmt must have the where_construct_name.

In a WHERE construct, only the WHERE construct statement can be labeled as a branch target statement.

The WHERE block is the set of assignments between the WHERE construct statement and the ELSEWHERE statement (or END WHERE statement, if the ELSEWHERE statement is not present). The ELSEWHERE block is the set of assignment statements between the ELSEWHERE and the END WHERE statements.

Each assignment in the ELSEWHERE block assigns a value to each array element that corresponds with a mask array element that is false.

The ELSEWHERE block is optional; when it is not present, no assignment is made to elements corresponding to mask array elements that are false.

All of the assignment statements are executed in sequence as they appear in the construct (in both the WHERE and ELSEWHERE blocks).

Any elemental intrinsic operation or function within an array assignment statement is evaluated only for the selected elements. In the following example, the square roots are taken only of the elements of A that are positive:

REAL  A(10, 20)
  ...
WHERE (A > 0.0)
  SQRT_A = SQRT(A)
END WHERE

An elemental function reference is evaluated independently for each element, and only those elements needed in the array assignment are referenced. A where_assignment_stmt that is a defined assignment must be elemental.

The expression in the array assignment statement can contain nonelemental function references. Nonelemental function references are references to any function or operation defined by a subprogram, without the ELEMENTAL keyword. All elements of the arguments of such functions and returned results (if arrays) are evaluated in full. If the result of the nonelemental function is an array and is an operand of an elemental operation or function, then only the selected elements are used in evaluating the remainder of the expression.

Example 1:

REAL  A(2, 3), B(3, 10), C(2, 10), D(2, 10)
INTRINSIC  MATMUL
  ...
WHERE (D < 0.0)
  C = MATMUL(A, B)
END WHERE

The matrix product A multiplied by B is performed, yielding all elements of the product, and only for those elements of D that are negative are the assignments to the corresponding elements of C made.

Example 2:

WHERE (TEMPERATURES > 90.0)  HOT_TEMPS = TEMPERATURES
WHERE (TEMPERATURES < 32.0)  COLD_TEMPS = TEMPERATURES

Example 3:

WHERE (TEMPERATURES > 90.0)
   NUMBER_OF_SWEATERS = 0
ELSEWHERE (TEMPERATURES < 0.0)
   NUMBER_OF_SWEATERS = 3
ELSEWHERE (TEMPERATURES < 40)
   NUMBER_OF_SWEATERS = 2
ELSEWHERE
   NUMBER_OF_SWEATERS = 1
ENDWHERE

7.5.4.2. Differences between the WHERE Construct and Control Constructs

One major difference between the WHERE construct and control constructs has been described in Section 7.5.4. Another difference is that no transfers out of WHERE or ELSEWHERE blocks are possible (except by a function reference) because only intrinsic assignment statements are permitted within these blocks. Note that the execution of statements in the WHERE block can affect variables referenced in the ELSEWHERE block (because the statements in both blocks are executed).

7.5.5. FORALL Statement and Construct

FORALL statements and constructs control the execution of assignment and pointer assignment statements with selection by using index values and an optional mask expression.

7.5.5.1. FORALL Construct

The FORALL construct allows multiple assignments, masked array (WHERE) assignments, and nested FORALL constructs and statements to be controlled by a single forall_triplet_spec_list and scalar_mask.

The format of the FORALL construct is as follows:

Table 7-31.

 

forall_construct

is

forall_construct_stmt
   [ forall_body_construct ] ...
   end_forall_stmt

 

forall_construct_stmt

is

[ forall_construct_name: ] FORALL forall_header

 

forall_header

is

(forall_triplet_spec_list [, scalar_mask_expr])

 

forall_triplet_spec

is

index_name = subscript : subscript [: stride]

 

subscript

is

scalar_int_expr

 

stride

is

scalar_int_expr

 

forall_body_construct

is

forall_assignment_stmt

 

 

or

where_stmt

 

 

or

where_construct

 

 

or

forall_construct

 

 

or

forall_stmt

 

forall_assignment_stmt

is

assignment_stmt

 

 

or

pointer_assignment_stmt

 

end_forall_stmt

is

END FORALL [ forall_construct_name ]

If the forall_construct_stmt has a forall_construct_name, the end_forall_stmt must have the same forall_construct_name. If the end_forall_stmt has a forall_construct_name, the forall_construct_stmt must have the same forall_construct_name.

The scalar_mask_expr must be scalar and of type logical.

A procedure that is referenced in the scalar_mask_expr, including one referenced by a defined operation, must be a pure procedure.

A procedure that is referenced in a forall_body_construct, including one referenced by a defined operation or assignment, must be a pure procedure.

The index_name must be a named scalar variable of type integer.

A subscript or stride in a forall_triplet_spec must not contain a reference to any index_name in the forall_triplet_spec_list in which it appears.

A statement in a forall_body_construct must not define an index_name of the forall_construct.

A forall_body_construct must not be a branch target.

Example:

REAL :: A(10, 10), B(10, 10) = 1.0
...
FORALL (I = 1:10, J = 1:10, B(I, J) /= 0.0)
   A(I, J) = REAL (I + J - 2)
   B(I, J) = A(I, J) + B(I, J) * REAL (I * J)
END FORALL

Each forall_body_construct is executed in the order in which it appears. Each construct is executed for all active combinations of the index_name values.

Execution of a forall_assignment_stmt that is an assignment_stmt causes the evaluation of expr and all expressions within variable for all active combinations of index_name values. After all evaluations have been performed, each expr value is assigned to the corresponding variable.

Execution of a forall_assignment_stmt that is a pointer_assignment_stmt causes the evaluation of all expressions within target and pointer_object, the determination of any pointers within pointer_object, and the determination of the target for all active combinations of index_name values. After these evaluations have been performed, each pointer_object is associated with the corresponding target.

In a forall_assignment_stmt, a defined assignment subroutine must not reference any variable that becomes defined or a pointer_object that becomes associated by the statement.

The following code fragment shows a FORALL construct with two assignment statements. The assignment to array B uses the values of array A computed in the previous statement, not the values A had prior to execution of the FORALL:

FORALL (I = 2:N-1, J = 2:N-1 )
   A (I, J) = A(I, J-1) + A(I,J+1) + A(I-1,J) + A(I+1, J)
   B (I, J) = 1.0 / A(I, J)
END FORALL

The following code fragment shows how to avoid an error condition by using an appropriate scalar_mask_expr that limits the active combinations of the index_name values:

FORALL (I = 1:N, Y(I) .NE. 0.0)
   X(I) = 1.0 / Y(I)
END FORALL

Each statement in a where_construct within a forall_construct is executed in sequence. When a where_stmt, where_construct_stmt, or masked_elsewhere_stmt is executed, the statement's mask_expr is evaluated for all active combinations of index_name values as determined by the outer forall_constructs, masked by any control mask corresponding to outer where_constructs. Any where_assignment_stmt is executed for all active combinations of index_name values, masked by the control mask in effect for the where_assignment_stmt. The following FORALL construct contains a WHERE statement and an assignment statement:

INTEGER A(5,4), B(5,4)
FORALL ( I = 1:5 )
   WHERE ( A(I,:) .EQ. 0 ) A(I,:) = I
   B (I,:) = I / A(I,:)
END FORALL

The preceding code is executed with array A as follows::

    0 0 0 0
    1 1 1 0
A = 2 2 0 2
    1 0 2 3
    0 0 0 0

The result is as follows:

    1 1 1 1         1 1 1 1
    1 1 1 2         2 2 2 1
A = 2 2 3 2     B = 1 1 1 1
    1 4 2 3         4 1 2 1
    5 5 5 5         1 1 1 1

When a forall_stmt or forall_construct is executed, the compiler evaluates the subscript and stride expressions in the forall_triplet_spec_list for all active combinations of the index_name values of the outer FORALL construct. The set of combinations of index_name values for the inner FORALL is the union of the sets defined by these bounds and strides for each active combination of the outer index_name values; it also includes the outer index_name values. The scalar_mask_expr is then evaluated for all combinations of the index_name values of the inner construct to produce a set of active combinations for the inner construct. If no scalar_mask_expr is specified, the compiler uses .TRUE. as its value. Each statement in the inner FORALL is then executed for each active combination of the index_name values. The following FORALL construct contains a nested FORALL construct. It assigns the transpose of the lower triangle of array A, which is the section below the main diagonal, to the upper triangle of A. The code fragment is as follows:

INTEGER A (3, 3)
FORALL (I = 1:N-1 )
   FORALL ( J=I+1:N )
      A(I,J) = A(J,I)
   END FORALL
END FORALL

Prior to execution of the preceding code, N=3 and array A is as follows:

    0 3 6
A = 1 4 7
    2 5 8

After the preceding code is executed, array A is as follows:

    0 1 2
A = 1 4 5
    2 5 8

You could also use the following FORALL statement to obtain identical results:

FORALL ( I = 1:N-1, J=1:N, J > I ) A(I,J) = A(J,I)

For more information on the FORALL statement, see Section 7.5.5.2.

7.5.5.2. FORALL Statement

The FORALL statement allows a single assignment statement or pointer assignment to be controlled by a set of values and an optional mask expression. The format for this statement is as follows:

Table 7-32.

 

forall_stmt

is

FORALL forall_header forall_assignment_stmt

Execution of a FORALL statement starts with the evaluation of the forall_triplet_spec_list for each index_name variable. All possible combinations of the values of the index_name variables are considered for execution of the FORALL body. The mask expression, if present, is then evaluated for each combination of index_name values and each combination that has a .TRUE. outcome is in the active combination of index_name values. This set of active combinations is then used in executing the FORALL body.

A FORALL statement is equivalent to a FORALL construct that contains a single forall_body_construct that is a forall_assignment_stmt.

The scope of an index_name in a forall_stmt is the statement itself.

The following FORALL statement assigns the elements of vector X to the elements of the main diagonal of matrix A:

FORALL (I=1:N) A(I,I) = X(I)

In the following FORALL statement, array element X(I,J) is assigned the value (1.0 / REAL (I+J-1)) for values of I and J between 1 and N, inclusive:

FORALL (I = 1:N, J = 1:N) X(I,J) = 1.0 / REAL (I+J-1)

The following statement takes the reciprocal of each nonzero off-diagonal element of array Y(1:N, 1:N) and assigns it to the corresponding element of array X. Elements of Y that are zero or are on the diagonal do not participate, and no assignments are made to the corresponding elements of X:

FORALL (I=1:N, J=1:N, Y(I,J) /= 0 .AND. I /= J) X(I,J) = 1.0 / Y(I,J)

7.5.5.3. Restrictions on FORALL Constructs and Statements

A many-to-one assignment is more than one assignment to the same object or subobject, or association of more than one target with the same pointer, whether the object is referenced directly or indirectly through a pointer. A many-to-one assignment must not occur within a single statement in a FORALL construct or statement. It is possible to assign, or pointer assign, to the same object in different assignment statements in a FORALL construct.

The appearance of each index_name in the identification of the left-hand side of an assignment statement is helpful in eliminating many-to-one assignments, but it is not sufficient to guarantee that there will be none. The following code fragment is permitted only if INDEX(1:10) contains no repeated values:

FORALL (I = 1:10)
   A (INDEX (I)) = B(I)
END FORALL

Within the scope of a FORALL construct, a nested FORALL statement or FORALL construct cannot have the same index_name. The forall_header expressions within a nested FORALL can depend on the values of outer index_name variables.