NAG Fortran Compiler, Release 7.2: Data declaration [mostly 6.0]

Navigation: Previous Up Next

## 10.3 Data declaration [mostly 6.0]

- The maximum rank of an array has been increased from 7 to 15. For example,

         REAL array(2,2,2,2,2,2,2,2,2,2,2,2,2,2,2)

  declares a 15-dimensional array.
- [3.0] 64-bit integer support is required, that is, the result of `SELECTED_INT_KIND(18)` is a valid integer kind number.
- A named constant (`PARAMETER`) that is an array can assume its shape from its defining expression; this is called an implied-shape array. The syntax is that the upper bound of every dimension must be an asterisk, for example

         REAL,PARAMETER :: idmat3(*,*) = Reshape( [ 1,0,0,0,1,0,0,0,1 ], [ 3,3 ] )
         REAL,PARAMETER :: yeardata(2000:*) = [ 1,2,3,4,5,6,7,8,9 ]

  declares `idmat3` to have the bounds `(1:3,1:3)`, and `yeardata` to have the bounds `(2000:2008)`.
- The `TYPE` keyword can be used to declare entities of intrinsic type, simply by putting the intrinsic type-spec within the parentheses. For example,

         TYPE(REAL) x
         TYPE(COMPLEX(KIND(0d0))) y
         TYPE(CHARACTER(LEN=80)) z

  is completely equivalent, apart from being more confusing, to

         REAL x
         COMPLEX(KIND(0d0)) y
         CHARACTER(LEN=80) z

- As a consequence of the preceding extension, it is no longer permitted to define a derived type that has the name `DOUBLEPRECISION`.
- [5.3] A type-bound procedure declaration statement may now declare multiple type-bound procedures. For example, instead of

            PROCEDURE,NOPASS :: a
            PROCEDURE,NOPASS :: b=>x
            PROCEDURE,NOPASS :: c

  the single statement

            PROCEDURE,NOPASS :: a, b=>x, c

  will suffice.
- [5.3 for `C_ASSOCIATED`, 7.0 for `C_LOC` and `C_FUNLOC`] A specification expression may now use the `C_ASSOCIATED`, `C_LOC` and `C_FUNLOC` functions from the `ISO_C_BINDING` module. For example, given a `TYPE(C_PTR)` variable X and another interoperable variable `Y` with the `TARGET` attribute,

             INTEGER workspace(MERGE(10,20,C_ASSOCIATED(X,C_LOC(Y))))

  is allowed, and will give `workspace` a size of 10 elements if the C pointer `X` is associated with `Y`, and 20 elements otherwise.
- [7.0] A specification expression may now use a user-defined operation, provided that operation is provided by a specification function. (A specification function must be a pure function that is not a statement function or internal function, and that does not have a dummy procedure argument.) For example, given the interface block

             INTERFACE OPERATOR(.user.)
                PURE INTEGER FUNCTION userfun(x)
                   REAL,INTENT(IN) :: x
                END FUNCTION
             END INTERFACE

  the user-defined operator `.user.` may be used in a specification expression as follows:

             LOGICAL mask(.user.(3.145))

  Note that this applies to overloaded intrinsic operators as well as user-defined operators.

- [7.1] An allocatable component can forward-reference a type, for example:

             Type t2
               Type(t),Pointer :: p
               Type(t),Allocatable :: a
             End Type
             Type t
               Integer c
             End Type

  An allocatable component can also be of recursive type, or two types can be mutually recursive. For example,

             Type t
               Integer v
               Type(t),Allocatable :: a
             End Type

  This allows lists and trees to be built using allocatable components. Building or traversing such data structures will usually require recursive procedure calls, as there is no allocatable analogue of pointer assignment.

  No matter how deeply nested such recursive data structures become, they can never be circular (again, because there is no pointer assignment). As usual, deallocating the top object of such a structure will recursively deallocate all its allocatable components.

- [7.1] A dummy argument can be used in a specification expression in an elemental subprogram, as long as it is not used to specify a type parameter (such as character length) of a function result. For type parameters of function results, they remain limited to appearing in specification enquiries (such as `LEN`) when the enquiry is not about a deferred characteristic.

  For example, in

        Elemental Subroutine s(x,n,y)
          Real,Intent(In) :: x
          Integer,Intent(In) :: n
          Real,Intent(Out) :: y
          Real temp(n)
          ...

  the dummy argument `N` can be used to declare the local array `TEMP`.
- [7.1] Pointers and pointer components can be initialised to point to a target. The target must be valid for that pointer (e.g. same type, rank, etc.). The main cases are:
  Named pointer initialisation
    For data pointers, the target must have the `SAVE` attribute (variables in modules and the main program have this attribute implicitly). For procedure pointers, the target must be a module procedure or external procedure, not a dummy procedure, internal procedure, or statement function.

    For example,

          Module m
            Real,Target :: x
            Real,Pointer :: p => x
          End Module
          Program test
            Use m
            p = 3
            Print *,x ! Will print the value 3.0
          End Program

  Component default initialisation
    Pointer components can be default-initialised to point to a target. The requirements on the target are the same as for named pointer initialisation.

    For example,

          Module m
            Real,Target :: x
            Type t
              Real,Pointer :: p => x
            End Type
          End Module
          Program test
            Use m
            Type(t) y
            y%p = 3
            Print *,x ! Will print the value 3.0
          End Program

  Component initialisation with structure constructors
    A structure constructor in a constant expression can specify a target for any pointer component. The requirements on the target are the same as for named pointer initialisation.

    For example,

          Module m
            Real,Target :: x
            Type t
              Real,Pointer :: p
            End Type
          End Module
          Program test
            Use m
            Type(t) :: y = t(x)
            y%p = 3
            Print *,x ! Will print the value 3.0
          End Program

- [7.1] A reference to a function that returns a pointer can be used as a variable in many contexts. In particular, it can be used as the variable in an assignment statement, as the actual argument corresponding to an `INTENT(OUT)` or `INTENT(INOUT)` dummy argument, and as the selector in an `ASSOCIATE` or `SELECT TYPE` construct that modifies the associate-name.

  For example, with this module,

        Module m
          Real,Target,Save :: table(100) = 0
        Contains
          Function f(n)
            Integer,Intent(In) :: n
            Real,Pointer :: f
            f => table(Min(Max(1,n),Size(table)))
          End Function
        End Module

  the program below will print “`-1.23E+02`”.

        Program example
          Use m
          f(13) = -123
          Print 1,f(13)
        1 Format(ES10.3)
        End Program

  It should be noted that the syntax of a statement function definition is identical to part of the syntax of a pointer function reference as a variable; the existence of a pointer-valued function that is accessible in the scope determines which of these it is. This may lead to confusing error messages in some situations.

  With the above module, this program demonstrates the use of the feature with an `ASSOCIATE` construct.

        Program assoc_eg
          Use m
          Associate(x=>f(3), y=>f(4))
            x = 0.5
            y = 3/x
          End Associate
          Print 1,table(3:4) ! Will print "  5.00E-01  6.00E+00"
        1 Format(2ES10.2)
        End Program

  Finally, here is an example using argument passing.

        Program argument_eg
          Use m
          Call set(f(7))
          Print 1,table(7) ! Will print "1.41421"
        1 Format(F7.5)
        Contains
          Subroutine set(x)
            Real,Intent(Out) :: x
            x = Sqrt(2.0)
          End Subroutine
        End Program

  Other contexts where a reference to a pointer-valued function may be used instead of a variable designator include:

  - as an internal file specifier in a `WRITE` statement (the function must return a pointer to a character string or array for this);
  - as an input-item in a `READ` statement;
  - as a `STAT=` or `ERRMSG=` variable in an `ALLOCATE` or `DEALLOCATE` statement, or in an image control statement such as `EVENT WAIT`;
  - as the team variable in a `FORM TEAM` statement.
- [7.1] The result of a function can be a procedure pointer. For example,

        Module ppfun
          Private
          Abstract Interface
            Subroutine charsub(string)
              Character(*),Intent(In) :: string
            End Subroutine
          End Interface
          Public charsub,hello_goodbye
        Contains
          Subroutine hello(string)
            Character(*),Intent(In) :: string
            Print *,'Hello: ',string
          End Subroutine
          Subroutine bye(string)
            Character(*),Intent(In) :: string
            Print *,'Goodbye: ',string
            Stop
          End Subroutine
          Function hello_goodbye(flag)
            Logical,Intent(In) :: flag
            Procedure(hello),Pointer :: hello_goodbye
            If (flag) Then
              hello_goodbye => hello
            Else
              hello_goodbye => bye
            End If
          End Function
        End Module
        Program example
          Use ppfun
          Procedure(charsub),Pointer :: pp
          pp => hello_goodbye(.True.)
          Call pp('One')
          pp => hello_goodbye(.False.)
          Call pp('Two')
        End Program

  The function `hello_goodbye` in module `ppfun` returns a pointer to a procedure, which needs to be pointer-assigned to a procedure pointer to be invoked. When executed, this example will print

       Hello: One
       Goodbye: Two

  Use of this feature is not recommended, as it blurs the lines between data objects and procedures; this may lead to confusion or misunderstandings during code maintenance. The feature provides no functionality that was not already provided by procedure pointer components.