It is assumed that the reader is already familiar with fact that, within the PROCEDURE DIVISION of a COBOL (sub)program, each paragraph is a unit of executable code that is "callable" ---via the PERFORM verb--- from within that (sub)program. In effect, all the paragraphs in (the PROCEDURE DIVISION of) a COBOL (sub)program are parameter-less "routines" having access to the same data, namely, all those data items declared in the DATA DIVISION of that (sub)program.
In contrast, a COBOL subprogram is a separate compilation unit; that is, it belongs in a file by itself and is compiled independently of its clients (i.e., other COBOL (sub)programs that call it). In order to produce an executable file, the object code files produced by the separate compilations of a main program and any subprograms it calls (directly or indirectly) must be linked. (You may wish to read instructions on how to compile, link, and execute COBOL programs in a VMS environment.)
Because the data declared in one compilation unit is not visible in any other (and hence, subprograms cannot communicate with their callers through the mechanism of shared data, as do the paragraphs within a compilation unit), subprograms communicate with their callers through the mechanism of argument-passing. (What are called "parameters" in some languages are referred to as "arguments" in others, including COBOL and FORTRAN.)
The syntactic form of a COBOL subprogram is nearly identical to that of a COBOL program; in particular, it has the same four divisions: IDENTIFICATION, ENVIRONMENT, DATA, and PROCEDURE.
In a subprogram, however, the DATA DIVISION includes ---in addition to the FILE and WORKING-STORAGE sections--- a LINKAGE section, where the subprogram's formal arguments are described (via PICTURE clauses, etc.)
Another syntactic difference is that, in a subprogram, the PROCEDURE DIVISION header includes a USING clause that lists the names of the formal arguments and, in so doing, indicates the order in which the corresponding actual arguments must be listed by the caller in making a call to the subprogram.
Finally, to terminate execution of a subprogram (and return control to its caller), the statement EXIT PROGRAM is used, rather than STOP RUN. The latter statement will, as usual, have the effect of terminating execution of the whole program; in other words, if it is executed within a subprogram, control will not return to its caller.
A statement used for calling a subprogram has the syntax
For example, the following invokes the subprogram Junk and passes to it four arguments, the first and last BY REFERENCE and the middle two BY CONTENT:
CALL 'Junk' USING BY REFERENCE Garbage BY CONTENT Refuse, 37 BY REFERENCE Rubbish
For another example, note that the PROGRAM-ID of this subprogram is Plus-One; then note that, to call it, another (sub)program would (most likely) use a statement of the form
Note: This concept is not unique to COBOL. FORTRAN works like this too. In Algol-60, a language of great historical importance, you can specify in a variable's declaration that its value is to persist from one invocation to the next by using the keyword own. In C you can get this effect using "static" variables. In Ada, variables declared inside a package (but not local to any of its subprograms) behave similarly. End of note.
By using a CANCEL statement, the syntax of which is
a calling program forces the local variables of the indicated subprogram to be "refreshed". Thus, if a calling (sub)program requires that the data items in a subprogram be in a refreshed state each time it invokes that subprogram, it should precede each CALL to that subprogram with a CANCEL statement.
Another way to ensure that all data items local to a subprogram
are refreshed each time it is called is to insert the phrase
IS INITIAL PROGRAM (both IS and PROGRAM
are optional) immediately after the subprogram's
name in its PROGRAM-ID paragraph. For example,
This is an extremely powerful and dangerous feature, and one that you would expect to find in a language such as LISP that readily supports AI applications, but not in a data processing language!
The second interesting point is that it is the caller, rather than the subprogram, which determines the mode under which each argument is passed. (Did you notice this during the discussion of the CALL verb above?) In Pascal and Ada, for example, the mode of each formal parameter is specified in the definition of the subprogram. That is, the subprogram determines the mode of parameter passing for each parameter. By giving control of this to the caller, it makes it impossible to describe a subprogram's effects in terms of a single pre- and post-condition pair. Instead, (in the worst case) you'd need a distinct pair of conditions for each of the possible 2k choices of passing the arguments, where k is the # of arguments.
For a much more complete description of subprograms (and nested programs) in COBOL, see Chapter 23 of Comprehensive COBOL.