A COBOL batch job can spend a surprising amount of time transferring control between programs. The cost is small for one call, but it matters when a transaction driver calls the same validation module millions of times. The right choice depends on whether the subprogram name is fixed, whether the module must be loaded separately, and how the application is maintained.
What does CALL do in COBOL?
The CALL statement transfers control from one COBOL program to another program in the same run unit. The calling program passes data with the USING phrase, and the called program receives that data in its PROCEDURE DIVISION USING list.
CALL "TAXCALC" USING WS-GROSS-PAY
WS-TAX-AMOUNT
END-CALL
That example uses a CALL literal because the program name is hard-coded. A CALL identifier uses a data item to hold the program name, which lets the job choose the target at run time.
Static, dynamic, and nested calls at a glance
| Call style | Typical coding | Best fit | Tradeoff |
|---|---|---|---|
| Nested call | CALL "INNER-PGM" inside a containing program |
Small helper logic that belongs inside one program source | Less flexible for separate reuse |
| Static call | CALL "TAXCALC" with NODYNAM |
Fixed subprogram names and stable batch applications | Relink needed when called modules change |
| Dynamic call | CALL WS-PROG-NAME or CALL literal with DYNAM |
Selectable routines, shared utility modules, plugin-style processing | Runtime load and library lookup must be managed |
CALL literal and CALL identifier
A CALL literal is easier for a reviewer to trace because the target name appears in the source. With NODYNAM, a nonnested CALL literal is normally handled as a static call. With DYNAM, that same source can behave like a dynamic call.
CALL "RATEEDIT" USING WS-RATE-AREA
A CALL identifier is dynamic. The program name comes from a working-storage item, parameter, file, or table. This is useful when one driver program chooses between several routines, but it also makes production diagnosis harder because the target module is not obvious from the statement alone.
01 WS-CALL-NAME PIC X(08) VALUE "RATEEDIT".
CALL WS-CALL-NAME USING WS-RATE-AREA
ON EXCEPTION
DISPLAY "CALL FAILED: " WS-CALL-NAME
END-CALL
Nested program calls
A nested program is coded inside another COBOL program. IBM documents nested calls as a structured way to keep helper logic close to the containing program and to reduce accidental changes to unrelated data. Nested programs can be called with a literal or identifier, subject to the scope rules of contained programs.
IDENTIFICATION DIVISION.
PROGRAM-ID. PAYDRVR.
PROCEDURE DIVISION.
CALL "EDIT-PAY" USING WS-PAY-DATA
GOBACK.
IDENTIFICATION DIVISION.
PROGRAM-ID. EDIT-PAY.
PROCEDURE DIVISION USING LS-PAY-DATA.
GOBACK.
END PROGRAM EDIT-PAY.
END PROGRAM PAYDRVR.
Use nested programs for local helper routines that are not meant to be called across many load modules. Avoid them when the routine is a shared service that many programs must update independently.
Static CALL performance
A static call is usually faster to enter because the called program is resolved through link-edit or binder processing rather than found and loaded at run time. It also gives build-time visibility: if the called object is missing, the build process is more likely to expose the problem before the batch job starts.
The cost is maintenance. Static calls can make the load module larger, and a changed subprogram may require relink work. In a shop with many shared routines, that can turn one utility change into a batch of packaging work.
Dynamic CALL performance
Dynamic calls give the application more freedom. A program can call a module by name at run time, and a changed called program can often be replaced without rebuilding every caller. That is why dynamic calls are common for utility routines and configurable processing.
The tradeoff is runtime control. The correct module must be available through the job's load library search path, such as STEPLIB or site-standard runtime libraries. If the module is missing or the name is wrong, the failure happens during execution instead of during link-edit.
DYNAM and NODYNAM
The DYNAM compiler option tells Enterprise COBOL to treat nonnested, separately compiled CALL literal statements as dynamic calls. NODYNAM is the usual static choice for a fixed CALL literal. A CALL identifier is dynamic regardless of that option.
CALL "PAYCALC" *> literal: static with NODYNAM, dynamic with DYNAM
CALL WS-PROG-NAME *> identifier: dynamic
Do not decide this option from one statement alone. Check the compile option list, binder control, runtime libraries, and whether the program contains features with site restrictions, such as CICS or embedded SQL rules at your installation.
Parameter passing affects support more than speed
Most production issues around CALL do not come from the transfer itself. They come from mismatched parameters. IBM documents three common passing methods: BY REFERENCE, BY CONTENT, and BY VALUE.
| Method | What the called program gets | Support note |
|---|---|---|
BY REFERENCE |
Access to the caller's storage | Changes in the called program affect the caller's data item. |
BY CONTENT |
A copy of the caller's content | The called program cannot change the original caller item. |
BY VALUE |
A value, often for non-COBOL linkage | Useful for C/C++ style calls, but both sides must agree. |
Production checklist for CALL-heavy programs
- List the top repeated calls in the job before changing compiler options.
- Use
CALL literalwhen the target program name is fixed and easy tracing matters. - Use
CALL identifieronly when the target truly needs to vary at run time. - Check whether
DYNAMorNODYNAMis used by the compile JCL. - Verify the called module is available in the expected load library.
- Match every
CALL USINGitem with the called program's linkage layout. - Add
ON EXCEPTIONhandling when a missing dynamic target should produce a clean message.
Common mistakes
Changing DYNAM without checking all calls
A compiler-option change can alter how fixed-name calls are loaded. Review every frequent CALL literal, especially in batch drivers and shared utility modules.
Using CALL identifier for a fixed name
If the target never changes, a literal is usually clearer. An identifier hides the target and makes source searches less useful during a production incident.
Passing the wrong layout
The called program does not know your intent. If the caller sends a 50-byte area and the callee expects 80 bytes, the symptom may appear as bad data, a protection exception, or a later logic error.
Related Mainframe Forum guides
For surrounding topics, read COBOL DYNAM Compiler Option, COBOL Application Structure, COBOL CALL by Reference, Content, and Value, COBOL CALL Statement, Static Call in COBOL, and COBOL RENT Compiler Option.
External references
IBM documents these rules in the Enterprise COBOL CALL statement, transferring control to another program, calling nested COBOL programs, and passing data pages.
FAQ
Is a static CALL always faster than a dynamic CALL?
Static calls usually avoid runtime load and lookup work, so they are often faster for repeated fixed-name calls. Measure the full job before changing a production compile option.
Is CALL identifier static or dynamic?
CALL identifier is dynamic. The target program name is taken from the value of the identifier at run time.
When should I use a nested COBOL program?
Use a nested program when the helper logic belongs inside one containing program and does not need to be separately shared by many applications.
What should I check first when a dynamic CALL fails?
Check the program name value, load library search path, compile option, and whether the called module exists under the expected name.