Previous Table of Contents Next


1.2.14.3. Pure Procedures

With the advent of parallel processing, problems associated with side effects become decidedly more pronounced than in a single processor environment. This is the case in calling a function in a forall construct, for example, in which the execution order is indeterminate. For the computational result to be determinate, the function must not have side effects such as changing values in common or writing intermediate results to a file. Pure procedures are intended to disallow the side effects that impact determinancy. Pure procedures have a number of other advantages as well, such as making possible the use of user-defined functions in specification expressions.

All the intrinsic functions and the mvbits intrinsic subroutine are pure procedures. The prefix specification pure in a user-defined function or subroutine statement specifies that procedure to be pure. There are four contexts in which a procedure must be pure:

  A function referenced in a forall construct
  A function referenced in a specification statement
  A procedure that is passed as an actual argument to a pure procedure
  A procedure referenced in the body of a pure procedure (including those referenced by a defined operator or defined assignment)

1.2.14.4. Elemental Procedures

The purpose of elemental procedures is to allow the programmer to define a procedure with scalar arguments and the elemental keyword that can be called with array arguments of any rank.

An elemental procedure has all scalar dummy arguments; in addition, an elemental function delivers a scalar result. The expressive power of elemental procedures comes from the provision that the actual arguments may be arrays of any rank, as long as all the actual arguments in a given call to an elemental procedure are in general conformable. The result of an elemental call having array actual arguments is the same as would have been obtained if the procedure had been applied separately, in any order (including simultaneously), to the corresponding elements of each argument.

The prefix specification elemental in a user-defined function or subroutine statement specifies that procedure to be elemental. Here is an example:

   elemental function vip_calc(x, y)

      real :: vip_calc
      real, intent(in) :: x, y
         . . .
   end function vip_calc

      x = vip_calc(1.1, 2.2) ! A call to vip_calc with scalar arguments
      ax = vip_calc(a(1:n), b(1:n))
   ! The result of this call is an array
   !  conformable with a(1:n) and b(1:n).

1.2.15. Arrays

The name of an array obeys the same rules as an ordinary variable name. Each array must be declared in the declaration section of program, module, or procedure. A name is declared to be an array by putting the dimension attribute in a type statement followed by a range of subscripts, enclosed in parentheses:

   real, dimension (1 : 9) :: x, y
   logical, dimension (-99 : 99) :: yes_no

In a function or subroutine, the range of a dummy argument may consist of just the colon, possibly preceded by a lower bound, and the subscript range is determined by the corresponding actual argument passed to the procedure. This sort of dummy argument is called an assumed-shape array. If no lower bound is given, the subscript range is from 1 to the size of the array, in each dimension:

   subroutine s (d)
      integer, dimension (:, :, 0:), intent (in) :: d

An array of character strings may be declared in a form such as the following:

   character (len = 8), dimension (0 : 17) :: char_list

In this example, the variable char_list is an array of 18 character strings, each of length 8.

The shape of an array is a list of the number of elements in each dimension. A 9 × 7 array has shape (9,7); the array char_list declared above has shape (18); and the array declared by

   integer, dimension (9, 0:99, -99:99) :: iii

has shape (9,100,199). When only one number is given in a dimension declaration in place of a subscript range, it is used as the upper subscript bound and the lower bound is 1.

The shape of a scalar is a list with no elements in it. The shape of a scalar or array can be computed using the shape intrinsic function.

1.2.15.1. Array Constructors

An array constructor is a convenient way to give an array a set of values. An array constructor is a list of values, separated by commas and delimited by the pair of two-character symbols (/ and /).

There are three possible forms for the array constructor values:

  A scalar expression, as in
   x (1:4) = (/ 1.2, 3.5, 1.1, 1.5 /)
  An array expression, as in
   x (1:4) = (/ a (i, 1:2), a (i+1, 2:3) /)
  An implied do loop, as in
   x (1:4) = (/ (sqrt (real (i)), i = 1, 4) /)

If there are no values specified in an array constructor, the resulting array is zero sized. The values of the components must have the same type and type parameters (kind and length). The rank of an array constructor is always one; however, the reshape intrinsic function can be used to define rank-two to rank-seven arrays from the array constructor values where

   reshape ( (/ 1, 2, 3, 4, 5, 6 /), (/ 2, 3 /) )

is the 2 × 3 array

1.2.15.2. Dynamic Arrays

By giving an array the allocatable or pointer attribute, memory may be allocated for the array during execution of the program:

   real, dimension (:,:), allocatable :: data_array
      . . .
   read *, n
   allocate (data_array (n,n+1))

The deallocate statement may be used to free the allocated storage.


Previous Table of Contents Next