Global Variables

In C and C++, the term "global variable" refers to an object which is accessible from any module within the load module. In COBOL II, such a variable is said to be EXTERNAL.

The term GLOBAL applies in COBOL II only in the context of nested programs. A GLOBAL variable corresponds, in C or C++, to a static variable at file scope.

Though the syntax differs, these two kinds of variables involve similar issues of design. For simplicity I shall refer to both types as global. (Besides, I have a nice icon of a globe. It's hard to come up with any kind of icon for EXTERNAL.)

Simulating Global Variables

There are two other ways in which different COBOL modules may share the same variable:
  1. A subprogram may access a variable passed to it as a parameter.
  2. A program may access any variable to which it has a pointer, either passed as a parameter or returned by a subprogram.
A variable in a subprogram is effectively global if there are entry points available both to return its value and to update it. Using this approach, you can provide the equivalent of global variables even in a dialect which does not support global variables directly.

Alternatively, an entry point could return a pointer to the variable. The calling program could then dereference the pointer and either read or update the variable. However, this approach is awkward in COBOL II, since you can't directly take the address of something in WORKING-STORAGE.

In JOCKEY, the JK015 module provides a generic facility for storing and retrieving global variables by name. The same module provides a form of environmental variable: it loads variables from a file, and thereafter treats them as simulated global variables.

To define, redefine, or undefine a simulated global variable, call JKPUTENV. To retrieve its value, call JKGETENV. In each case, one of the parameters is a name specifying the variable you want to access.

Failure to Initialize a Global Variable

Typically when you use a global variable, module A needs to populate the variable so that module B can use it. Since an EXTERNAL variable cannot have a VALUE clause, it can be initialized only in the PROCEDURE DIVISION.

What if module A has a bug? It might forget to initialize the variable, or even to define it. B has no way to verify that the contents of the variable are not utter garbage.

In JOCKEY, the JK015 module reports SPACES as the value of any variable which has not been defined, or which has been undefined. By this means module B can protect itself from a faulty module A.

Warning

Use a global variable -- whether real or simulated -- only as a last resort. It adds an element of coupling between any two modules which use it, thereby making maintenance more complicated.

For example, suppose module A sets the value of a global variable so that module B may use that value. It may not be obvious to a maintenance programmer that A must execute before B. If he calls them in the wrong sequence, the resulting problems may be difficult to debug or even detect.

Use global variables only when the usual parameter-passing mechanism is clumsy or impractical. There are two main situations where global variables may be appropriate:

  1. You initialize a variable at the beginning of a run and then leave it alone. This approach is especially useful in IMS programs for PCBs (see below).
  2. You use global variables to pass detailed information about fatal error conditions back up to the main program.

Making PCBs Global

One of the ugliest aspects of IMS is the need for a PCB in the LINKAGE SECTION. You can't just call IMS whenever you want; you have to get the PCB from the main program.

Traditionally, large IMS programs constantly pass PCBs around. If a subprogram six levels down needs a new PCB due to new requirements, you have to pass it all the way down, possibly through levels which don't even use the PCB themselves.

You can eliminate most of this clumsiness by making the PCBs global. You can't store the PCBs themselves, since they reside inside IMS somewhere. You could store global copies of the PCBs, but you couldn't use the copies for an IMS call.

The solution is to store global pointers to the PCBs. Any module which needs to make an IMS call can grab the appropriate pointer, dereference it to a PCB in the LINKAGE SECTION, and call IMS. Other modules in the calling chain don't even have to know that IMS exists (except for the main module, which receives the PCBs in the first place and stores the pointers).

(Apparently I am not the only one to have come up with this scheme. See the note from Lars Bjerges.)


[home]COBOL Home [meadow]Environmental Variables