Chapter 6. Scope, Association, and Definition

Scope, association, and definition (value assignment) provide the communication pathways between the different parts of the program. These topics were not presented completely in previous chapters because a comprehensive and thorough understanding of the entire language is needed to fully assimilate these topics. Fortunately, all of the detailed rules and conditions presented in this chapter usually are not necessary in order to construct pieces of Fortran programs. If simple programming disciplines are followed, many of the subtle issues and concerns related to scope, association, and definition can be avoided in writing correct programs. However, there are some situations in which it is necessary to know all the details, particularly when modifying or maintaining programs, or looking for subtle bugs.

The concept of scope is introduced in the Fortran Language Reference Manual, Volume 1. Scope specifies that part of a program in which a particular entity is known and accessible. The spectrum of scope varies from an entire program (global), to individual program units (local), to construct definitions, to statements or parts of statements.

To both communicate data between program units and limit and control accessibility of data, the language defines the concept of association, which relates local objects within and between program units. The association methods were introduced in previous sections and include association through arguments (argument association), association through storage (storage association), association through modules (use association), association through hosts (host association), and association through name aliases (pointer association).

After objects are associated, there can be multiple ways to define values for them. For example, assignment statements and input statements define objects directly by name, which can also cause associated items to become defined. In some cases, such associated object values can be unpredictable or unreliable. For example, if a real object is equivalenced (storage associated) with an integer object, defining the real object with a valid real value causes the integer object to acquire a meaningless value. This meaningless value is called an undefined value. In certain cases, such as for the integer object in the preceding example, certain values are considered to be undefined; references to undefined values do not conform to the standard.

Thus, the three topics -- scope, association, and definition -- are related. Scope specifies the part of a program where an entity is known and accessible. Association is the pathway along which entities in the same or different scopes communicate. Definition, and its opposite, undefinition, characterize the ways in which variables are defined and become undefined indirectly as a consequence of being associated with other objects.

Scope

Named entities such as variables, constants, procedures, constructs, block data subprograms, modules, and namelist groups, have scope. Other (unnamed) entities that have scope are operator symbols, the assignment symbol, labels, and input/output (I/O) unit numbers.

The scope of an entity is that part of a Fortran program in which that entity has a given meaning and can be used, defined, or referenced by its designator. The scope of an entity might be as large as the whole executable program or as small as part of a Fortran statement. Entities that can be used with the same meaning throughout the executable program are said to be global entities and have a global scope. An example of a global entity is an external procedure name.

Entities that can be used only within the smaller context of a subprogram are said to be local entities and have a local scope. An example of a local entity is a statement label. An even smaller context for scope might be a Fortran statement (or part of one); entities valid for only this context are said to be statement entities, such as the dummy arguments in a statement function. If the scope is a construct, the entity is called a construct entity.

A scoping unit can contain other scoping units. A scoping unit surrounded by another scoping unit may or may not inherit properties from the surrounding scope. For example, internal procedures, module procedures, and derived-type definitions inherit implicit typing rules from the surrounding scope. An interface body, on the other hand, is an example of a scope that is nonoverlapping, as opposed to nested. An interface body in a subprogram causes a hole in the subprogram scoping unit that is filled with the scoping unit of the interface body. This means that an interface body, for example, does not inherit implicit typing rules from the surrounding scope.

A scoping unit is one of the following:

  • A derived-type definition

  • A procedure interface body, excluding any derived-type definitions and procedure interface bodies contained within it

  • A program unit or subprogram, excluding derived-type definitions, procedure interface bodies, and subprograms contained within it

To visualize the concept of scope and scoping units, consider Figure 6-1. The outer rectangle defines the boundary of the pieces of an executable Fortran program; it is not a scoping unit, but it could be said to represent global scope. Within the executable program four other rectangles depict program units. One is the main program, two others are external subprogram units, and the fourth one is a module program unit.

Figure 6-1. Scoping units

Scoping units

All four of these program unit rectangles represent scoping units, excluding any rectangles within them. The main program in this example encloses no rectangle and so is an integral scoping unit without holes. External subprogram A has two internal procedures within it, and therefore procedure A's scoping unit is this rectangle, excluding internal procedures B and C. External subprogram D has an interface body in it and no internal procedures. Its scoping unit is procedure D, excluding the interface bodies in the interface block. Module E has a derived-type definition and two module procedures within it. Its scoping unit is similarly the module program unit, excluding the derived-type definition and the module procedures.

In addition, the interface bodies within the interface block, the derived-type definition, and each of the internal and module procedures are scoping units. In this example, these latter scoping units have no holes, as they do not themselves contain internal procedures, module procedures, interface bodies, or derived-type definitions, although they could in general.

Scope of Names

A name has one of the following scopes:

  • A global scope, which is the scope of an executable program (for example, an external function name)

  • A local scope, which is the scope of a scoping unit (for example, an array name in a subroutine subprogram)

  • A statement scope, which is the scope of a Fortran statement (for example, a statement function argument) or a part of a Fortran statement (for example, an implied-DO variable in a DATA statement)

Names As Global Entities

The name of a main program, an external procedure, a module, a block data program unit, or a common block has global scope. No two program unit names can have the same name; that is, a module cannot have the same name as an external subroutine. The CF90 and MIPSpro 7 Fortran 90 compilers, however, allow a common block to have the same name as a program unit.


Note: The Fortran standard does not allow two global entities to have the same name.


Names As Local Entities

There are three classes of names that have local scope:

  • Names of variables, constants, control constructs, statement functions, internal procedures, module procedures, dummy procedures, intrinsic procedures, user-defined generic procedures, derived types, and namelist groups.

  • Names of the components of a derived type. There is a separate class of names for each derived type, which means that two different derived types can have the same component names.

  • Names of argument keywords. There is a separate class of names for each procedure with an explicit interface, which means that two different procedures can have the same argument keyword names.

A global entity name cannot be used to identify a local entity, except that a local entity can have the same name as a common block.

A nongeneric local name is unique within a scoping unit and within a name class; that is, it identifies exactly one entity. That name can also be used to identify a different object in a different scoping unit or a different object in a different class in the same scoping unit. When that name or a different name is used in other scoping units, it usually represents a different entity but may represent the same entity because of association.

A generic local name can be used for two or more different procedures in that scoping unit.

A local name can be used for another local entity in a different class in that scoping unit. For example, a structure component of type logical can have the same name as a local integer variable.

Components of a derived type have the scope of the derived-type definition, and when used in a qualified structure reference have the scope of the structure reference itself.

Argument keywords are local entities, and are in a separate class for each procedure with an explicit interface. This means that an argument keyword used for one procedure can be used as an argument keyword for another procedure, as a local variable or procedure name, and as a component name of a derived type.

If a common block name is the same as the name of a local entity, the name is the local entity except where it appears to identify the common block. Uniqueness of the reference is determined by the context of the name. For example, a name enclosed in slashes in a SAVE statement is a common block name rather than the name of a local variable of the same name.

The name of an intrinsic procedure can be used as a local entity provided the intrinsic procedure itself is not used in that scoping unit. For example, if the scoping unit uses the name SIN as a local variable name, the intrinsic function SIN may not be used in the same program unit.

For each function and function entry that does not have a result variable, there is a local variable within the function subprogram scoping unit whose name is the same as the function or entry name. This local variable is used to define the value of the function or entry name within the function subprogram.

For each internal or module procedure, the name of the procedure is also a name local to the host scoping unit. Similarly, for any entry name used in a module procedure, the name of the entry is also a name local to the host scoping unit.

Names As Statement and Construct Entities

The name of a dummy argument in a statement function statement, or a DO variable in an implied-DO list of a DATA statement or array constructor, has a scope that is the statement or part of the statement. Such a name can be used elsewhere as a variable name or common block name without a name conflict and refers to a different entity when so used.


Note: The Fortran standard states that the variable whose name is duplicated by the statement entity must be a scalar variable.

The name of a dummy argument used in a statement function statement has the scope of the statement. The type and type parameters of the name are determined by the declarations in the containing scoping unit.

The DO variable in an array constructor or an implied-DO loop in a DATA statement has the scope of that part of the statement in which it appears. The type, which must be integer, and type parameters of the name are determined by the declarations in the containing scoping unit.

The name of a variable that appears in an index_name of a FORALL statement or FORALL construct has the scope of the statement or construct. It must be a scalar variable that has the type and type parameters that it would have if it were the name of a variable in the scoping unit that includes the FORALL. It must be of type integer and have no other attributes.

If the name of a global or local entity that is accessible to the scoping unit of a FORALL statement or FORALL construct is the same as the index_name, the name is interpreted within the scope of the FORALL statement or FORALL construct as that of the index_name. Elsewhere in the scoping unit, the name is interpreted as that of the global or local entity.

The scope of the DO variable in these implied-DO lists is part of a statement, whereas the scope of the DO variable in a DO construct is local to the scoping unit containing the DO construct. Similarly, the DO variable of an implied-DO in an I/O item list has the scope of the program unit containing the I/O statement.

Scope of Labels

A label is a local entity. No two statements in the same scoping unit can have the same label, but the same label can be used in different scoping units.

Scope of Input/output (I/O) Units

External I/O unit numbers are global entities and have global scope. Within an executable program, a unit number refers to the same I/O unit wherever it appears in a unit number context in an I/O statement.

Scope of Operators

Intrinsic operators have global scope; the scope of a defined operator is local to a scoping unit. An operator symbol can refer to both an intrinsic operator and a defined operator. For example, the operator symbol (+) can be both global (its intrinsic meaning) and local (its defined meaning). Operators can be generic; that is, two or more operators can be designated by the same operator symbol. The types, kind parameter values, and the ranks of the operands distinguish which operator is used.

Scope of Assignment

Intrinsic assignment has global scope; defined assignment has the scope of a scoping unit. The assignment symbol (=) always has global meanings and may, like operator symbols, also have local meanings. Assignment is generic; many assignment operations are designated by the same operator symbol. The types, kind parameter values, and the ranks of the entities on the left and right sides of the equal sign distinguish which assignment is used.

Unambiguous Procedure References

A procedure reference is unambiguous if the procedure name in the reference is a specific procedure name that is not the same as any generic procedure name in that scoping unit. This is the case in references to the following items:

  • Internal procedures

  • Module and external procedures not appearing in an interface block with a generic specification in that scoping unit or available through use or host association

  • Nongeneric specific names of intrinsic functions

  • Statement functions

  • Dummy procedures

Procedure references that involve generic procedure names can be unambiguous under certain circumstances. Specific names of external and intrinsic procedures are global; all other specific procedure names are local.

It is possible to have two procedures with the same generic name. Within the same scoping unit, the procedures must both be subroutines or must both be functions. In addition, one of the following must also be true of their dummy argument lists:

  • One of them must have more nonoptional dummy arguments of a particular data type, kind type parameter, and rank than the other has dummy arguments (including optional dummy arguments) of that data type, kind type parameter, and rank.

  • At least one of them must have both of the following:

    • A nonoptional dummy argument that corresponds by position in the argument list to a dummy argument that is not present in the other, present with a different type, present with a different kind type parameter, or present with a different rank.

    • A nonoptional dummy argument that corresponds by argument keyword to a dummy argument that is not present in the other, present with a different kind type parameter, or present with a different rank.

    In addition, the dummy argument that disambiguates by position must be either the same as or occur earlier in the argument list than the one that disambiguates by keyword.

These rules apply regardless of whether the generic names are intrinsic, defined by interface blocks with generic specifications, or both. They also apply to generic operator and assignment symbols. Generic names of intrinsic functions are global, and defined generic names are local.

Resolving Procedure References

A procedure reference is involved in the following situations:

  1. Executing a CALL statement

  2. Executing a defined assignment statement

  3. Evaluating a defined operation

  4. Evaluating an expression containing a function reference

In case 2, a generic name (the assignment symbol, =) is involved, and there must be an interface block with an ASSIGNMENT generic specification in the scoping unit or available through use or host association that identifies a specific external or module subroutine that defines this assignment. “Resolving References to Generic Procedures” in Chapter 4, “Defined Assignment” in Chapter 4, and “Unambiguous Procedure References”, contain information that can help determine the specific subroutines involved in the reference.

In case 3, a generic name (the operator symbol) is involved, and there must be an interface block with an OPERATOR generic specification in the scoping unit or available through use or host association that identifies a specific external or module function that defines this operation. “Resolving References to Generic Procedures” in Chapter 4, “Defined Operators” in Chapter 4, and “Unambiguous Procedure References”, contain information that can help determine the specific function involved in the reference.

In cases 1 and 4, the following sequence of rules can be used to resolve the reference (that is, determine which specific procedure is involved in the reference). The first of these rules that applies, taken in order, resolves the reference.

  1. If the procedure name in the reference is a dummy argument in that scoping unit, then the dummy argument is a dummy procedure and the reference is to that dummy procedure. Thus, the procedure invoked by the reference is the procedure supplied as the associated actual argument.

  2. If the procedure name appears in an EXTERNAL statement or interface body in that scoping unit, the reference is to an external procedure with that name.

  3. If the procedure name is that of an accessible internal procedure, module subprogram, or statement function, the reference is to that internal procedure or statement function.

  4. If the procedure name is specified as a generic name in an interface block in that scoping unit or in an interface block made accessible by use or host association, and the reference is consistent with one of the specific interfaces for that generic name, the reference is to that specific procedure. “Argument Association” in Chapter 4, contains information that can help determine the specific procedure invoked (there will be at most one such procedure).

  5. If the reference is consistant with an elemental reference to one of the specific interfaces of a generic interface that has that name and either is in the scoping unit in which the reference appears or is made accessible by a USE statement in the scoping unit, the reference is to the specific elemental procedure in that interface block that provides the interface.

  6. If the procedure name appears in an INTRINSIC statement or is USE associated from a module that has the INTRINSIC attribute declared for it, the reference is to the corresponding specific intrinsic procedure in that scoping unit.

  7. If the procedure name is accessible through use association, the reference is to that specific procedure. Note that it is possible, because of the renaming facility, for the procedure name in the reference to be different from that in the module.

  8. If the scoping unit of the reference has a host scoping unit, and if application in the host of the preceding six rules resolves the reference, then the reference is so resolved.

  9. The reference is to the corresponding specific intrinsic procedure if the following are true:

    • The procedure name is either the specific or generic name of an intrinsic procedure.

    • The actual arguments match the characteristics of a particular intrinsic procedure.

  10. If the procedure name is not a generic name, the reference is to an external procedure with that name.

  11. Otherwise the reference cannot be resolved and is not standard conforming.

Association

Fortran uses the concept of scoping so that the same name can be used for different things in different parts of a program. This is desirable so that programmers do not have to worry about conflicting uses of a name.

However, there are times when just the opposite is desired: the programmer wants different names in the same or different parts of a program to refer to the same entity. For example, there may be a need to have one data value that can be examined and modified by all of the procedures of a program. In general, particularly with external program units, the names used will be different in the different parts of the program, but they can be the same.

The association mechanism is used to indicate that local names in different scoping units or different local names in the same scoping unit refer to the same entity. The forms of association are as follows:

  • Name association, which involves the use of names, always in different scoping units, to establish an association.

  • Pointer association, which allows dynamic association of names within a scoping unit and is essentially an aliasing mechanism.

  • Storage association, which involves the use of storage sequences to establish an association between data objects. The association can be between two objects in the same scoping unit (EQUIVALENCE) or in different scoping units (COMMON).

  • Sequence association, which is a combination of name association and storage association. It applies to the association of actual arguments and array, character, and sequence structure dummy arguments using storage sequence association. It associates names in different scoping units.

Figure 6-2 and Figure 6-3, illustrate the various kinds of association in an executable program.

Figure 6-2. Associations between two nonmodule scoping units

Associations between two nonmodule scoping units

Figure 6-3. Associations between a module scoping unit and a nonmodule scoping unit

Associations between a module scoping unit and a nonmodule scoping unit

Name Association

Name association permits access to the same entity (either data or a procedure) from different scoping units by the same or a different name. There are three forms of name association: argument, use, and host.

Argument Association

Argument association is explained in detail in “Argument Association” in Chapter 4. It establishes a correspondence between the actual argument in the scoping unit containing the procedure reference and the dummy argument in the scoping unit defining the procedure. An actual argument can be the name of a variable or procedure, or it can be an expression. The dummy argument name is used in the procedure definition to refer to the actual argument, whether it is a name or an expression. When the program returns from the procedure, the actual and dummy arguments become disassociated.

Use Association

Use association causes an association between entities in the scoping unit of a module and the scoping unit containing a USE statement referring to the module. It provides access to entities specified in the module. The default situation is that all public entities in the module are accessed by the name used in the module, but entities can be renamed selectively in the USE statement and excluded with the ONLY option. Use association is explained in “Use Association” in Chapter 3.

If renaming occurs by a USE statement, the type, type parameters, and other attributes of the local name are those of the module entity. No respecification can occur in the scoping unit containing the USE statement, other than another module adding the PRIVATE attribute.

When an entity is renamed by a USE statement, the original name in the module can be used as a local name for a different entity in the scoping unit containing the USE statement. There would be no name conflict.

The PUBLIC and PRIVATE access specifications are determined in the module referenced in the USE statement. The PUBLIC attribute can be overridden by the referencing scoping unit if the referencing scoping unit is a module (see the example in “Use Association” in Chapter 3, for an exception to this).

Host Association

Host association causes an association between entities in a host scoping unit and the scoping unit of an internal procedure, module procedure, or derived-type definition. The basic idea of host association is that entities in the host (for example, host variables) are also available in any procedures or derived-type definitions within the host. As with default use association, such entities are known by the same name in the internal or module procedure or derived-type definition as they are known in the host. There is no mechanism for renaming entities, but the association of names between the host and the contained scoping unit can be replaced by the local declaration of an entity with that name; such a declaration blocks access to the entity of the same name in the host scoping unit.

The program unit containing an internal procedure is called the host of the internal procedure. The program unit (which must be a module) that contains a module procedure is called the host of the module procedure. As shown in Figure 6-4, an important property of internal and module procedures is that the data environment of the host is available to the procedure. When data in the host are available within the contained procedure, they are said to be accessible by host association. Because the internal (or module) procedure also has a local data environment, rules are needed to determine whether a given reference inside that procedure identifies a host entity or one local to the procedure.

An interface body cannot access named entities by host association. An interface body can access entities by USE association.

Figure 6-4. Host association

Host association

In a language in which the attributes of all entities must be declared explicitly, local declarations typically override host declarations. The host declarations that are not overridden are available in the contained procedure. Fundamentally these are the rules used in Fortran, and this situation can be simulated by using IMPLICIT NONE in both the host and the contained procedure. IMPLICIT NONE forces explicit declaration of all entities.

However, Fortran allows implicit declarations (the use of an entity name in the execution part without an explicit declaration of that name in the specification part). Suppose the variable TOTAL is referenced in an internal procedure, and neither the internal procedure nor its host explicitly declares TOTAL. Is TOTAL a host or local entity? Or, suppose that TOTAL is used in two internal procedures in the same host, without declaration anywhere. Are they (or it) the same TOTAL? The possibilities are shown in Figure 6-5.

Figure 6-5. Is there one TOTAL in the host or two local TOTALs?

Is there one  TOTAL in the host or two local  TOTALs?

The answer to both of these questions is case (b) in Figure 6-5, unless TOTAL is also referenced in the host, in which case (a) applies. If TOTAL is referenced in the host, it becomes declared implicitly there and is therefore a host entity. In this case, any internal procedure use of TOTAL accesses the host entity. The situation is the same (TOTAL is a host entity) if it is declared but not referenced in the host and not declared in the internal procedure. If TOTAL is declared in the internal procedure, then case (b) applies (TOTAL is local) regardless of whether TOTAL is declared or referenced in the host.

Implicit declarations are governed by the implicit typing rules and the use of the IMPLICIT statement. The rules governing implicit typing in hosts and contained procedures are given in the Fortran Language Reference Manual, Volume 1, and the rules governing host association are given in “Host Association”. These rules are combined and summarized in the following paragraphs.

A name is local if it is declared explicitly in the contained procedure, regardless of any declarations in the host. A dummy argument in a contained procedure is an explicit local declaration, even though the name can be implicitly typed. A dummy argument, if not explicitly typed, is typed according to the implicit typing rules of the contained procedure.

An entity not declared explicitly in a contained procedure is nevertheless local (via implicit declaration) if and only if it is neither explicitly nor implicitly declared in the host.

If it is not local, based on the previous paragraphs, the entity is host associated.

The default implicit rules (the implicit typing rules in the absence of IMPLICIT statements) in a contained procedure are the implicit typing rules of the host, as established by the default implicit rules in the host and modified by any IMPLICIT statements in the host.

IMPLICIT statements in the contained procedure, if any, modify the implicit typing rules inherited from the host. Note that these modified rules apply to implicitly typed dummy arguments of the contained procedure.

The following is a summary of the implicit typing rules:

host implicit typing rules

=

host default implicit rules

+

host IMPLICIT statements

 

    

contained procedure typing rules

=

host implicit typing rules

+

contained procedure IMPLICIT statements

In the expression X = A+B+P+Q+Y in the following program example, the operands in the expression are declared in different scoping units (see Figure 6-6):

PROGRAM HOST
   USE GLOBAL_DATA      ! Accesses integer X and real Y.
   IMPLICIT LOGICAL (E-J)
   ! implicit typing: A-D real
   !                  E-J logical
   !                  K-N integer
   !                  O-Z real
   REAL  A, B
      . . .
   READ *, P            ! This reference declares P
                        ! implicitly here.
      . . .
   CALL CALC(Z)         ! This reference also implicitly
      . . .             ! declares Z here.
CONTAINS
      . . .
   ! X declared explicitly in internal procedure CALC.
   SUBROUTINE CALC(X)
      IMPLICIT REAL(G-I)
      ! implicit typing: A-D real
      !                  E-F logical
      !                  G-I real
      !                    J logical
      !                  K-N integer
      !                  O-Z real
      REAL  B
         . . .
      X = A + B + P + Q + Y
      ! In subroutine CALC (all are type real):
      !    X is local (dummy argument)
      !    A is host associated
      !    B is local (explicitly declared)
      !    P is host associated
      !    Q is local (implicitly declared)
      !    Y host associated with Y in HOST,
      !      and that Y is use associated (from the module)
         . . .
   END SUBROUTINE CALC
   . . .
END PROGRAM HOST

Figure 6-6. How the mapping of implicit typing progresses from host to contained procedure

How the mapping of implicit typing progresses from host to contained procedure

A particularly interesting case of the host associated implicit rules is when the host has IMPLICIT NONE. With IMPLICIT NONE, no other implicit statements are allowed in that scoping unit, and explicit typing is required for all data objects in the host. IMPLICIT NONE is therefore the default in the contained procedure, although this can be modified by IMPLICIT statements in the contained procedure. This can result in some of the letters having implicit types in the contained procedure and some not. For example, suppose that the host has IMPLICIT NONE and the contained procedure has the following IMPLICIT statements:

IMPLICIT COMPLEX (C, Z)
IMPLICIT LOGICAL (J-L)

Data objects in the contained procedure with names starting with C or Z may be declared implicitly of type complex; data objects with names starting with J, K, or L may be declared implicitly of type logical. IMPLICIT NONE continues to apply to letters A-B, D-I, and M-Y, and data object names beginning with these letters must be explicitly declared.

Pointer Association

A pointer is a variable with the POINTER attribute. During program execution, the pointer variable is undefined, disassociated, or associated with a scalar or an array data object or function result. The association of pointers is dynamic throughout a program; that is, the association can be changed as needed during execution. Pointers are initially undefined unless they are initialized, either explicitly or implicitly. A pointer can be initialized to have an association status of disassociated.

Pointers can be associated in one of the following ways:

  • By pointer assignment, pointers are associated with other pointers or with scalar or array data objects that have the TARGET attribute

  • By execution of an ALLOCATE statement, pointers are associated with previously unnamed space

Associated pointers can become disassociated or undefined. Disassociated pointers can become associated or undefined. Undefined pointers can become associated.

Associated pointers become disassociated when one of the following occurs:

  • The association is nullified (NULLIFY statement).

  • The pointer is deallocated (DEALLOCATE statement).

  • The pointer is assigned to a disassociated pointer.

  • The pointer becomes an ultimate component of an object of a type for which default initialization is specified for the component and one of the following conditions occurs or is present:

    • A function with this object as its result is invoked.

    • A procedure with this object as an INTENT(OUT) dummy argument is invoked.

    • A procedure with this object as an automatic object is invoked.

    • A procedure with this object as a local object that is not accessed by USE or host association is invoked.

    • This object is allocated.

The following events cause the association status of pointers to become undefined:

  • The pointer is pointer-associated to a target that has an undefined association status.

  • The target of the pointer is deallocated by a means other than through the pointer.

  • The execution of a RETURN or END statement causes the pointer's target to become undefined.

  • The execution of a RETURN or END statement in a subprogram in which the pointer was either declared or accessed. In the case of an access, the pointer becomes undefined under the following circumstances:

    • It is a pointer with the SAVE attribute.

    • It is a pointer in blank common.

    • It is a pointer in a named common block that appears in at least one other scoping unit that is currently executing.

    • It is a pointer in the scoping unit of a module, and the module is also accessed by another scoping unit that is currently executing.

    • The pointer is accessed by host association.

    • It is a pointer that is the return value of a function that has been declared to have the POINTER attribute.

Storage Association

Storage association is the provision that two or more variables can share the same memory space. This allows the same value to be referenced by more than one name, achieving an effect similar to that of name association and pointer association. Consider the following simple example:

EQUIVALENCE (X, Y)

Variables X and Y share the same memory location; changing the value of either one affects the value of the other.

The effects of EQUIVALENCE and COMMON statements can be complicated because of partially overlapping variables and storage association between different data types. The concept of storage association is used to describe these effects.

Storage Units and Storage Sequence

A storage unit corresponds to a particular part of memory that holds a single value. Thus, memory may be thought of as a sequence of storage units, each possibly holding a value. A storage unit can be a numeric storage unit, a character storage unit, or an unspecified storage unit.

A sequence of any number of consecutive storage units is a storage sequence. A storage sequence has a size, which is the number of storage units in the sequence.

Fortran Data and Storage Units

This section describes some of the relationships between Fortran data and storage units.

All of the following data objects are nonpointer values unless explicitly specified otherwise:

  • A scalar data object of type default integer, default real, or default logical occupies one numeric storage unit. Default complex and double-precision real values occupy two, consecutive, numeric storage units.

  • A single character occupies one character storage unit.

  • All other values, that is, pointers and all values with nondefault kinds, occupy unspecified storage units. An unspecified storage unit is treated as a different object for each of these types of values. For example, a storage unit for a pointer to a default integer occupies an unspecified storage unit that is different than the unspecified storage unit for an integer of nondefault type.

Composite objects occupy storage sequences, depending on their form, as follows:

  • A scalar character object of length len has len consecutive character storage units.

  • An array occupies a storage sequence consisting of one storage unit of the appropriate sort for each element of the array in array element order.

  • A scalar of a sequence derived type occupies a storage sequence consisting of storage units corresponding to the components of the structure, in the order they occur in the derived-type definition. Recall that to be a sequence type, the derived type must contain the SEQUENCE statement.

  • Each common block has a storage sequence as described in the Fortran Language Reference Manual, Volume 1.

  • Each ENTRY statement in a function subprogram has a storage sequence as described in “ENTRY Statement” in Chapter 4.

  • EQUIVALENCE statements create storage sequences from the storage units of the objects making up the equivalence lists.

Two objects that occupy the same storage sequence are storage associated. Two objects that occupy parts of the same storage sequence are partially storage associated.

A storage unit must not be explicitly initialized more than once in a program. Explicit initialization overrides default initialization, and default initialization for an object of derived type overrides default initialization for a component of the object. Default initialization can be specified for a storage unit that is storage associated if the objects or subobjects that supply the default initialization are of the same type and type parameters and if they supply the same value for the storage unit.

Partial Association

Partial association applies to character data and other composite objects in COMMON or EQUIVALENCE statements. When such objects only partially overlap in storage, they are then said to be partially associated. For example, two character strings are partially associated if substrings of each share the same storage but the entire strings do not.

Examples

This section contains examples of storage sequences of various sorts and illustrations of how equivalencing causes association of storage sequences and the data objects in them.

Example 1: This is a simple example involving numeric storage units. Consider the following code fragment:

COMPLEX :: C
REAL    :: X(0:5)
EQUIVALENCE (C, X(3))

The storage sequence occupied by C consists of two numeric storage units, one for the real part and one for the imaginary part.

The storage sequence occupied by X consists of six numeric storage units, one for each element of the array.

The EQUIVALENCE statement indicates that X(3) and the real part of C occupy the same storage unit, creating the following association (items above and below each other are storage associated):

Figure 6-7. Example 1

Example 1

Example 2: The following example deals with character data. Consider this code fragment:

CHARACTER A(2,2)*2, B(2)*3, C*5
EQUIVALENCE (A(2,1)(1:1), B(1)(2:3), C(3:5))

A, B, and C occupy character storage sequences of size 8, 6, and 5 respectively, and the EQUIVALENCE statement sets up the following associations:

Figure 6-8. Example 2

Example 2

Sequence Association

Sequence association is a special form of argument association that applies to character, array, and sequence structure arguments. For more information on sequence association, see “Sequence Association” in Chapter 4.

Definition Status

The value of a variable can be used safely when that value is well-defined and predictable. There are a number of things that can cause the value of a variable to become ill-defined or unpredictable during the course of program execution. Informally, defined is the term given to a variable whose value is well-defined and predictable. Undefined is the term given to a variable whose value is ill-defined or unpredictable.

Using undefined values does not conform to the standard. Unfortunately, either the compiler cannot always check for undefined conditions or it might be too costly to do so. It is your responsibility to avoid using undefined values.

During execution of a program, variables are said to be defined or undefined. If a variable is defined, it has a value established during some statement execution (or event) in the program. If a variable is undefined, it is considered to not have a value. Variables are initially undefined except for initial values specified in DATA statements and type statements, components of variables that are of a type for which default initialization is specified, and objects of zero size. (Zero-sized arrays and zero-length character strings are always defined). As execution proceeds, other events may cause a variable to become defined or undefined. Undefined variables must not be referenced in a context in which the value of the variable is used.

Definition Status of Subobjects

An array element or array section is part of an array. A substring is part of a character variable. A component is part of a structure. An object of type complex consists of two parts, its real and imaginary parts. All parts of an object must be defined for the object to be defined. If any part of an object is undefined, that object is undefined. Zero-sized arrays and zero-length character strings are always defined.

Events That Affect Definition Status of Variables

Assignment defines the value of the variable on the left of the equal sign. Similarly, reading input establishes values for variables in the input list. Certain specifier variables are defined when a statement such as the INQUIRE statement is executed.

Returning from a procedure causes all unsaved local variables to become undefined. Deallocation and disassociation during program execution causes variables to become undefined. In addition, the process of defining an entity can cause certain associated or partially associated entities to become undefined. Lists of events that cause variables to be defined and undefined are provided in the following sections.

Events That Cause Variables to Become Defined

Variables become defined when the following events occur:

  • Execution of an intrinsic assignment statement other than a masked array assignment statement or FORALL assignment statement causes the variable that precedes the equal sign to become defined. Execution of a defined assignment statement can cause all or part of the variable that precedes the equal sign to become defined.

  • Execution of a masked array assignment statement or FORALL assignment statement can cause some or all of the array elements in the assignment statement to become defined

  • As execution of an input statement proceeds, each variable that is assigned a value from the input file becomes defined at the time that data is transferred to it. Execution of a WRITE statement whose unit specifier identifies an internal file causes each record that is written to become defined.

  • Execution of a DO statement causes the DO variable, if any, to become defined.

  • Beginning execution of the action specified by an implied-DO list in an input/output (I/O) statement causes the implied-DO variable to become defined.

  • A reference to a procedure causes a dummy argument data object to become defined if the associated actual argument is defined with a value that is not a statement label. If only a subobject of an actual argument is defined, only the corresponding subobject of the associated dummy argument is defined.

  • Execution of an I/O statement containing an IOSTAT= specifier causes the specified integer variable to become defined.

  • Execution of a READ statement containing a SIZE= specifier causes the specified integer variable to become defined.

  • Execution of an INQUIRE statement causes any variable that is assigned a value during the execution of the statement to become defined if no error condition exists.

  • When a character storage unit becomes defined, all associated character storage units become defined.

  • When a numeric storage unit becomes defined, all associated numeric storage units of the same type become defined.

  • When an unspecified storage unit becomes defined, all associated unspecified storage units become defined.

  • When a default complex entity becomes defined, all partially associated default real entities become defined.

  • When both parts of a default complex entity become defined as a result of partially associated default real or default complex entities becoming defined, the default complex entity becomes defined.

  • When all components of a numeric sequence structure or character sequence structure become defined as a result of partially associated objects becoming defined, the structure becomes defined.

  • Execution of an ALLOCATE or DEALLOCATE statement with a STAT= specifier causes the variable specified by the STAT= specifier to become defined.

  • Execution of a pointer assignment statement that associates a pointer with a target that is defined causes the pointer to become defined.

  • Allocation of a zero-sized array causes the array to be defined.

  • Allocation of an object of a derived type, in which default initialization is specified for any nonpointer direct component, causes that component to become defined.

  • Invocation of a procedure that contains a nonsaved local object causes the components of the object to become defined if all of the following conditions are present:

    • The local object is not a dummy argument.

    • The local object is not accessed by USE or host association.

    • The local object has neither the ALLOCATABLE nor the POINTER attribute.

    • The local object is of a derived type in which default initialization is specified for its direct components.

  • Invocation of a procedure that has an INTENT(OUT) dummy argument of a derived type that specifies default initialization for a nonpointer direct component causes that component of the dummy argument to become defined.

  • Invocation of a nonpointer function of a derived type in which default initialization is specified for a nonpointer direct component causes that component of the function result to become defined.

  • In a FORALL construct, the index_name becomes defined when the index_name value set is evaluated.

Events That Cause Variables to Become Undefined

Variables become undefined when the following events occur:

  • When a variable of a given type becomes defined, all associated variables of different type become undefined. However, when a variable of type default real is partially associated with a variable of type default complex, the complex variable does not become undefined when the real variable becomes defined, and the real variable does not become undefined when the complex variable becomes defined. When a variable of type default complex is partially associated with another variable of type default complex, definition of one does not cause the other to become undefined.

  • If the evaluation of a function can cause an argument of the function or a variable in a module or in a common block to become defined, and if a reference to the function appears in an expression in which the value of the function is not needed to determine the value of the expression, the argument or variable becomes undefined when the expression is evaluated.

  • The execution of a RETURN statement or an END statement within a subprogram causes all variables local to its scoping unit or local to the current instance of its scoping unit for a recursive invocation to become undefined, except for the following:

    • Variables with the SAVE attribute

    • Variables in blank common

    • Variables in a named common block


      Note: The Fortran standard specifies that a variable in a named common block retains its value (remains defined) only if the common block also appears in at least one other scoping unit that is making either a direct or indirect reference to the current subprogram. The CF90 and MIPSpro 7 Fortran 90 compilers retain the value regardless of whether the common block also appears in any other currently active scoping unit.


    • Variables accessed from the host scoping unit

    • Variables accessed from a module that also is accessed in at least one other scoping unit that is making either a direct or indirect reference to the module

    • Variables in a named common block that are initially defined and that have not been subsequently defined or redefined

  • When an error condition or end-of-file condition occurs during execution of an input statement, all of the variables specified by the input list or namelist group of the statement become undefined.

  • When an error or end-of-file condition occurs during execution of an I/O statement that includes implied-DO loops, all of the implied-DO variables become undefined.

  • Execution of a defined assignment statement can leave all or part of the variable that precedes the equal sign undefined.

  • Execution of a direct access input statement that specifies a record that has not been written previously causes all of the variables specified by the input list of the statement to become undefined.

  • Execution of an INQUIRE statement can cause the NAME=, RECL=, and NEXTREC= variables to become undefined.

  • When a character storage unit becomes undefined, all associated character storage units become undefined.

  • When a numeric storage unit becomes undefined, all associated numeric storage units become undefined unless the undefinition is a result of defining an associated numeric storage unit of different type.

  • When an entity of double-precision real type becomes undefined, all totally associated entities of double-precision real type become undefined.

  • When an unspecified storage unit becomes undefined, all associated unspecified storage units become undefined.

  • A reference to a procedure causes part of a dummy argument to become undefined if the corresponding part of the actual argument is defined with a value that is a statement label.

  • When an allocatable array is deallocated, it becomes undefined. Successful execution of an ALLOCATE statement for which default initialization has not been specified creates an array that is undefined.

  • Execution of an INQUIRE statement causes all inquire specifier variables to become undefined if an error condition exists, except for the variable in the IOSTAT= specifier, if any.

  • When a procedure is invoked, variables become undefined under the following circumstances:

    • An optional dummy argument that is not associated with an actual argument is undefined

    • A dummy argument with INTENT(OUT) is undefined

    • An actual argument associated with a dummy argument with INTENT(OUT) becomes undefined unless it is a type for which default initialization is specified

    • A subobject of a dummy argument is undefined if the corresponding subobject of the actual argument is undefined

    • The result variable of a function is undefined unless it is a type for which default initialization is specified

  • When the association status of a pointer becomes undefined or disassociated, the pointer becomes undefined.

  • When the execution of a FORALL construct is complete, the index_name becomes undefined.