| Introduction
|
Aims |
To provide a brief introduction to building modular systems using separately compiled and/or contained subprograms. To explore the syntax, semantics, and use of the CALL verb. To examine how "state memory" is implemented in COBOL and to demonstrate the effects of the IS INITIAL clause and the CANCEL command. To examine how contained subprograms are implemented and to show how the IS GLOBAL clause may be used to implement a form of "Information Hiding". To show how the IS EXTERNAL clause may be used to set up an area of storage that may be accessed by any program in the run-unit. To introduce Structured Design and to summarize its criteria for achieving good quality subprograms. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Objectives |
By the end of this unit you should -
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Prerequisites |
Introduction to COBOL | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
The CALL verb | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Introduction
|
A large software system is not usually written as a single monolithic program. Instead, it consists of a main program and many independently compiled subprograms, linked together to form one executable run-unit. A subprogram is the name we give to a program that is invoked from another program. The object code of separately compiled subprograms has to be linked together into one executable run-unit by a special program called a "Linker". One purpose of the Linker is to resolve the subprogram names
(given in the PROGRAM-ID clause) into actual
physical addresses so that the computer can find a particular
subprogram when it is invoked. In a system consisting of a main program and linked subprograms, there must be a mechanism that allows one program to invoke another and to pass data to it. In many programming languages, the procedure or function call serves this purpose. In COBOL, the CALL verb is used to invoke one program from another. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
CALL verb semantics |
The CALL verb transfers control to a subprogram. When the subprogram has finished, control returns to the statement that follows the CALL in the calling program. The called program may be an independently compiled program, or it may be contained within the text of the calling program (i.e. it may be a contained subprogram). | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
CALL syntax and notes
Passing parameters of incorrect types
to a called program is a frequent source of program failure
(crashes).
|
CALL notes
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Parameter passing mechanisms |
In standard COBOL, the CALL verb has two
parameter passing mechanisms -
The diagrams and explanations below show how these mechanisms work. CALL..BY REFERENCE
CALL..BY CONTENT
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
CALL example
|
The example fragments below show how a CALL statement is made in a calling program to invoke and pass parameters to a subprogram (shown in outline).
The CALL statement in the
calling program.
Outline of the called program Notes Note that the subprogram has a LINKAGE SECTION where the parameters passed to it are defined. Note that the names of the parameters passed by the CALL statement in the main program are different from those in the called subprogram. This is because it is the positions of the parameters following their respective USING clauses that is significant, not the names used. In this case TempDate corresponds to DateParam and DateCheckResult to DateResult.
Passing parameters BY REFERENCE is the mechanism by which data is passed from a called subprogram to the main program. In this example, what is being passed back is a code indicating the success or failure of the validation. BY REFERENCE should be used only when you require a subprogram to pass data back to the main program. It is a principle of modular design (i.e. a design where the system is broken into a number of subprograms. rather than consisting of a single monolithic program) that the data connection between modules should be as limited as possible. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| State memory and the IS INITIAL clause |
The IS INITIAL phrase The next time it is called, it remembers its state from the previous call. Any files that were opened are still open, and any data-items that were assigned values still contain those values. Although it can be useful for a subprogram to remember its state from call to call, systems that contain subprograms. with "state memory" are often less reliable and more difficult to debug than those that do not. A subprogram can be forced into its initial state each time it is called, by including the IS INITIAL clause in the PROGRAM-ID. In the examples below, the subprogram "Steadfast" produces the same result every time it is called with the same parameter value. But "Fickle", because it remembers its state from the previous call, will produce different results when called with the same value.
In "Steadfast", no matter how many times we run the program, when the parameter value is the same - the result is the same. For instance, on the first and third runs of the program the parameter has the value 12 and each time the result is 62 (12+50).
In "Fickle" the result produced by running the program depends on what the program "remembers" from the last time it was run. In the example runs, even though the parameter value is the same on the first and third runs, the result produced is different. On the first run the result is 62 (12+50) but on the third run, even though the value of the parameter is still 12, the program "remembers" the value of RunningTotal from the previous run and produces a result of 79 (12+67). | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
State memory and the CANCEL verb |
Sometimes a program only needs "state memory" part of the time. That is, it needs to be reset to its initial state periodically. In COBOL this can be done by means of the CANCEL verb/command. The syntax of the CANCEL verb is as follows
When the CANCEL command is executed, the memory space occupied by the subprogram is freed and if the subprogram is called again it will be in its initial state (i.e. all files closed and the data-items initialized to their VALUE clauses). By using the following statements in our main program CALL "Fickle" USING BY CONTENT IncValue. CANCEL "Fickle" CALL "Fickle" USING BY CONTENT IncValue. we can force "Fickle" to act like "Steadfast". | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Subprogram clauses and verbs |
COBOL subprograms. are identical to standard COBOL programs with the following exceptions:
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Contained Subprograms | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Introduction |
COBOL subprograms can be independently compiled separate programs (linked into a single executable run-unit) or they can be contained within the text of a containing program. Contained subprograms. are very similar to the procedures (or user defined functions) found in other languages except that they are invoked with the CALL verb and are better protected against accidental data corruption.
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Defining a contained subprogram |
When contained subprograms are used, the end of the main program, and each subprogram, is signalled by means of the END PROGRAM statement. This has the format: END PROGRAM ProgramIdName. Contained subprograms have the following restrictions:
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
The IS GLOBAL clause |
As noted above, data-items declared outside the scope of a contained subprogram cannot be seen within the subprogram. Sometimes however, you may want to share some data-item within a number of contained subprograms. For instance, in the example program fragments below, we want both of our subprograms to be able to access the NameTable. When we want a data-item to be seen within contained subprograms we simply follow the item declaration with the IS GLOBAL clause. The IS GLOBAL clause specifies that the data item is to be visible within any subordinate contained subprograms.
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Information Hiding using the IS GLOBAL clause and contained subprograms |
Contained subprograms. seem to offer us the opportunity to create some form of Information Hiding. For instance, it looks as though we could create an Informational Strength module as defined by Myres (Myres, G.J. Composite/Structured Design. 1979) by hiding a table declaration within a containing program and then allowing access to it through the contained subprograms. (see diagram below).
Unfortunately, this arrangement is not allowed in COBOL because, although subprograms. may be nested, a contained subprogram can only be called by the immediate containing program or by a subprogram at the same level. So in the diagram above, the main program would not be allowed direct access to the contained subprograms. The only way any kind of Informational Strength module can be achieved is for the MainProgram to call the ContainerProgram and for the ContainerProgram to call the appropriate subprogram as shown below. To do this the MainProgram would have to pass some sort of code to the ContainerProgram to tell it which of the subprograms to use and the parameter list passed to the ContainerProgram would have to be wide enough to accommodate the needs of the contained subprograms. This does not cause much of a problem in the example below, but in a case where the contained programs had more significant data needs it could prove a serious drawback. Glenford Myres (Myres, G.J. Composite/Structured Design. 1979) has produced criteria for deciding whether a module (i.e. a subprogram) is good or bad. Module Coupling (i.e. the data connections between modules) is one of the criteria he considers. According to his criteria the ContainerProgram below exhibits both Stamp and Control coupling.
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| The IS COMMON PROGRAM clause |
A programmer pondering the problem outlined above - how to get an external program to make direct calls to the subprograms contained within a container might be excited to come across the IS COMMON PROGRAM clause. He might be forgiven for thinking for a moment that this clause was the solution to his problem. Sadly this is not the case. The only use of the IS COMMON PROGRAM clause is to allow a subprogram to call one of its sibling subprograms. (i.e. a subprogram at the same level). Contained subprograms can only call a subprogram at the same level if the called program uses the IS COMMON PROGRAM phrase in its PROGRAM-ID. For instance in the example below DisplayData is called by the main program and by its sibling InsertData but InsertData cannot call DisplayData. The syntax diagram for the IS INITIAL and IS COMMON clauses is shown below. As you can see from the diagram both the COMMON and INITIAL clauses may be used in combination. The words IS and PROGRAM are noise words which may be omitted.
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Example program using contained subprograms. and the IS COMMON PROGRAM and IS GLOBAL clauses |
In this example, SharedItem can be accessed in the main program and in each of the subprograms because this has been explicitly specified in the data declaration by using the IS GLOBAL clause. Note that "$ SET NESTCALL" is a compiler directive for Microfocus NetExpress telling the compiler to expect contained subprograms. It is not standard COBOL.
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Example program using the IS INITIAL and IS COMMON clauses and the CANCEL command. |
In the example below the "Fickle" and "Steadfast" subprograms are revisited. This time they have been incorporated into the text of a main, containing program. The first part of the main program calls "Fickle" and "Steadfast" to demonstrate the difference between a program that has state memory and one that does not. In the second part of the main program, "Fickle" is used with the CANCEL command to calculate the square of a number by repeated addition. After the square of a particular number has been calculated the CANCEL command is used to initialize "Fickle" so that the next number may be computed.
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
The IS EXTERNAL clause
|
The IS GLOBAL clause allows a program and its contained subprograms to share access to a data-item. The IS EXTERNAL clause does the same for any subprogram in a run-unit (i.e. any linked subprogram). But while the data-item that uses IS GLOBAL phrase only has to be declared in one place, each of the subprograms that wish to gain access to an EXTERNAL shared item must declare the item in exactly the same way. The animation below shows how the IS EXTERNAL clause works. In this animation there are four programs in the run-unit. Program B and Program D wish to communicate using a shared data. In COBOL they can do this by using the IS EXTERNAL clause to set up a shared area of memory but both both programs must contain the declarations below. These set up, and allow access to, the shared area. Example:
WORKING-STORAGE SECTION.
01 SharedRec IS EXTERNAL.
02 PartA PIC X(4).
02 PartB PIC 9(5).
The kind of hidden data communication between subprograms that is supported by the IS EXTERNAL clause is generally regarded as very poor practice. Myres (Myres, G.J. Composite/Structured Design. 1979), for instance, indicates that this "Common Coupling" is nearly the worst kind of module coupling possible. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Designing a modular system |
Anyone who considers creating a system that consists of subprograms and contained subprograms should not embark on such an undertaking without an sound understanding how such a system is designed and what makes a good subprogram and what does not. This kind of system design is called a modular design and the subprograms are called modules. There are a number of different methods/approaches to designing a modular system but Structured Design is probably the most successful. It is beyond the scope of this course to provide instruction in Structured Design but programmers tasked with creating a modular system should read these two texts. Page-Jones, Meilir, Practical guide to Structured Systems
Design - Second Edition, Myers, Glenford, Composite/Structured Design, Von Nostrand Reinhold 19 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Criteria for module goodness |
Although this course cannot provide instruction in Structured Design we can observe that the criteria for module goodness specified in that approach boils down to three things:
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Copyright NoticeThese COBOL course materials are the copyright property of Michael Coughlan. All rights reserved. No part of these course materials may be reproduced in any form or by any means - graphic, electronic, mechanical, photocopying, printing, recording, taping or stored in an information storage and retrieval system - without the written permission of the author. (c) Michael Coughlan Last updated : May 2002
mailto:michael.coughlan@ul.ie | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||