BY CONTENT and BY VALUE
BY REFERENCE gives the called program your actual field. That is what you
want for results, but it also means the subprogram can change anything you
pass, deliberately or by accident. COBOL has two other passing modes.
BY CONTENT: pass a copy
With BY CONTENT, the system copies your item into a temporary area and
passes the address of the copy. The subprogram sees the same bytes and can
even change them, but when it returns, your field is untouched.
A mode applies to every item that follows it until you name another one:
IDENTIFICATION DIVISION.
PROGRAM-ID. MODEDEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-A PIC X(4) VALUE "AAAA".
01 WS-B PIC X(4) VALUE "BBBB".
01 WS-C PIC X(4) VALUE "CCCC".
PROCEDURE DIVISION.
CALL "CLOBBER" USING BY REFERENCE WS-A
BY CONTENT WS-B WS-C
DISPLAY WS-A " " WS-B " " WS-C
CALL "CLOBBER" USING BY CONTENT "LIT1" "LIT2"
BY REFERENCE WS-C
DISPLAY WS-A " " WS-B " " WS-C
STOP RUN.
IDENTIFICATION DIVISION.
PROGRAM-ID. CLOBBER.
DATA DIVISION.
LINKAGE SECTION.
01 LS-1 PIC X(4).
01 LS-2 PIC X(4).
01 LS-3 PIC X(4).
PROCEDURE DIVISION USING LS-1 LS-2 LS-3.
DISPLAY "GOT " LS-1 " " LS-2 " " LS-3
MOVE "1111" TO LS-1
MOVE "2222" TO LS-2
MOVE "3333" TO LS-3
GOBACK.
END PROGRAM CLOBBER.
END PROGRAM MODEDEMO.
GOT AAAA BBBB CCCC
1111 BBBB CCCC
GOT LIT1 LIT2 CCCC
1111 BBBB 3333
CLOBBER overwrote all three parameters both times, but only the items
passed BY REFERENCE (WS-A on the first call, WS-C on the second)
changed in the caller.
Notice the second call passes literals. You can't pass a literal by
reference on IBM compilers, because there is no field for the subprogram
to write into; pass literals BY CONTENT.
When to use it:
- For input-only parameters to a routine you don't own, when your program relies on the value afterwards.
- For literals and constants.
- When a routine is known to use a parameter as scratch space, as some old utilities do.
The called program doesn't know or care which mode the caller used; its
LINKAGE SECTION looks the same either way.
BY VALUE: for C and system services
BY VALUE puts the value itself, not an address, into the argument list.
That is how C functions and many operating-system services expect
arguments, so BY VALUE is what you use to call them. Binary fields
(COMP-5) match C's integer types, and RETURNING receives the function's
return value:
IDENTIFICATION DIVISION.
PROGRAM-ID. CDEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-CH PIC S9(9) COMP-5 VALUE 97.
01 WS-UP PIC S9(9) COMP-5.
01 WS-OUT PIC 999.
PROCEDURE DIVISION.
CALL "toupper" USING BY VALUE WS-CH RETURNING WS-UP
MOVE WS-UP TO WS-OUT
DISPLAY "TOUPPER(97) = " WS-OUT
STOP RUN.
TOUPPER(97) = 065
That calls the C library's toupper on the character code for a and gets
back 65, the code for A. Between two COBOL programs, stick to
BY REFERENCE and BY CONTENT. GnuCOBOL even warns that BY VALUE in a
COBOL program's PROCEDURE DIVISION USING is unfinished.
On the job
On z/OS you'll see BY VALUE in calls to Language Environment
callable services (the CEE... routines) and to C or Java code, and
BY CONTENT wherever a program passes a literal such as a message
number to a shared error routine.
Your task
The customer team wants to spot duplicate customers keyed with different
spelling. The shared routine MATCHKEY (already in the starter as a
nested program; don't change it) builds a key from a name: letters only,
upper case.
LINKAGE SECTION.
01 LS-NAME PIC X(30).
01 LS-KEY PIC X(30).
PROCEDURE DIVISION USING LS-NAME LS-KEY.
Read its code: it upper-cases LS-NAME in place to do its work.
In NAMEKEYS, add the CALL so each name is printed exactly as it was
typed, followed by its key. For the input
03
Mary O'Neill
mary oneill
Jean-Luc Picard
the output is
Mary O'Neill -> MARYONEILL
mary oneill -> MARYONEILL
Jean-Luc Picard -> JEANLUCPICARD
Protect the name by choosing the right passing mode, not by copying it to another field first.