Scope Rules

Since a main program could contain many functions and in fact a function can contain other functions (i.e., nested functions), one may ask the following questions:

  1. Could a function use a variable declared in the main program?
  2. Could a main program use a variable declared in one of its function?
The scope rules answer these questions. In fact, scope rules tell us if an entity (i.e., variable, parameter and function) is "visible" or accessible at certain places. Thus, places where an entity can be accessed or visible is referred to the scope of that entity.

The simplest rule is the following:

Scope Rule 1 The scope of an entity is the program or function
in which it is declared.

Therefore, in the following, the scope of parameter PI and variables m and n is the main program, the scope of formal argument k and REAL variables f and g is function Funct1(), and the scope of formal arguments u and v is function Funct2().

PROGRAM  Scope_1
   IMPLICIT  NONE
   REAL, PARAMETER :: PI = 3.1415926
   INTEGER         :: m, n
      ...................
CONTAINS
   INTEGER FUNCTION  Funct1(k)
      IMPLICIT  NONE
      INTEGER, INTENT(IN) :: k
      REAL                :: f, g
         ..........
   END FUNCTION  Funct1

   REAL FUNCTION  Funct2(u, v)
      IMPLICIT  NONE
      REAL, INTENT(IN) :: u, v
         ..........
   END FUNCTION  Funct2
END PROGRAM  Scope_1

There is a direct consequence of Scope Rule 1. Since an entity declared in a function has a scope of that function, this entity cannot be seen from outside of the function. In the above example, formal argument k and variables f and g are declared within function Funct1(), they are only "visible" in function Funct1() and are not visible outside of Funct1(). In other words, since k, f and g are not "visible" from the main program and function Funct2(), they cannot be used in the main program and function Funct2(). Similarly, the main program and function Funct1() cannot use the formal arguments u and v and any entity declared in function Funct2().

Local Entities

Due to the above discussion, the entities declared in a function or in the main program are said local to that function or the main program. Thus, k, f and g are local to function Funct1(), u and v are local to function Funct2(), and PI, m and n are local to the main program.

Global Entities

Given a function f(), entities that are declared in all containing functions or the main program are said global to f(). In the above example, since variables m and n are declared in the main program, they are global to Funct1() and function Funct2(). However, variables f and g are not global to function Funct2(), since Funct1() does not contain Funct2(). Similarly, formal arguments u and v are not global to function Funct1().

This comes the second scope rule:

Scope Rule 2 A global entity is visible to all contained functions,
including the function in which that entity is declared.

Continue with the above example, since m and n are global to both functions Funct1() and Funct2(), they can be used in these two functions.

PROGRAM  Scope_2
   IMPLICIT  NONE
   INTEGER :: a = 1, b = 2, c = 3

   WRITE(*,*)  Add(a)
   c = 4
   WRITE(*,*)  Add(a)
   WRITE(*,*)  Mul(b,c)

CONTAINS
   INTEGER FUNCTION  Add(q)
      IMPLICIT  NONE
      INTEGER, INTENT(IN) :: q
      Add = q + c
   END FUNCTION  Add

   INTEGER FUNCTION  Mul(x, y)
      IMPLICIT  NONE
      INTEGER, INTENT(IN) :: x, y
      Mul = x * y
   END FUNCTION  Mul
END PROGRAM  Scope_2
In the above program, variables a, b and c are global to both functions Add() and Mul(). Therefore, since variable c used in function Add() is global to Add(), expression q + c means computing the sum of the value of the formal argument q and the value of global variable c. Therefore, the first WRITE produces 4 (= 1 + 3). Before the second WRITE, the value of c is changed to 4 in the main program. Hence, the second WRITE produces 5 (= 1 + 4). The third WRITE produces 8 (= 2 * 4).

Thus, the first two WRITEs produce different results even though their actual arguments are the same! This is usually refereed to as a side effect. Therefore, if it is possible, avoid using global variables in internal functions.

Let us continue with the above example. To remove side effect, one could add one more argument to function Add() for passing the value of c.

PROGRAM  Scope_2
   IMPLICIT  NONE
   INTEGER :: a = 1, b = 2, c = 3

   WRITE(*,*)  Add(a, c)
   c = 4
   WRITE(*,*)  Add(a, c)
   WRITE(*,*)  Mul(b,c)

CONTAINS
   INTEGER FUNCTION  Add(q, h)
      IMPLICIT  NONE
      INTEGER, INTENT(IN) :: q, h
      Add = q + h
   END FUNCTION  Add

   INTEGER FUNCTION  Mul(x, y)
      IMPLICIT  NONE
      INTEGER, INTENT(IN) :: x, y
      Mul = x * y
   END FUNCTION  Mul
END PROGRAM  Scope_2

What If There Are Name Conflicts?

Frequently we may have a local entity whose name is identical to the name of a global entity. To resolve this name conflict, we need the following new scope rule:

Scope Rule 3 An entity declared in the scope of another entity is always
a different entity even if their names are identical.

In the program below, the main program declares a variable i, which is global to function Sum(). However, i is also declared in function Sum(). According to Scope Rule 3 above, these two is are two different entities. More precisely, when the value of Sum()'s i is changed, this change will not affect the i in the main program and vice versa. This would save us a lot of time in finding variables with different names.

PROGRAM  Scope_3
   IMPLICIT  NONE
   INTEGER :: i, Max = 5

   DO i = 1, Max
      Write(*,*)  Sum(i)
   END DO

CONTAINS

   INTEGER FUNCTION  Sum(n)
      IMPLICIT  NONE
      INTEGER, INTENT(IN) :: n
      INTEGER             :: i, s
      s = 0
      DO i = 1, n
         s = s + i
      END DO
      Sum = s
   END FUNCTION  Sum
END PROGRAM  Scope_3