VALUE, INITIALIZE and Condition Names
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the section bibliography. |
This page is written against ISO/IEC 1989:2023 (edition 3, January 2023; an edition 4 is upcoming, in DIS ballot), GnuCOBOL 3.2
(28 July 2023, the latest release) and IBM Enterprise COBOL for z/OS 6.5 (PTFs through September 2026), and was checked on
2026-10-20. Every portable example below was compiled with cobc -x -Wall (GnuCOBOL 3.2.0, fixed reference format) without a
single warning and run; the output and the diagnostics shown are real. The ISO standard is paywalled and was not read: the rules
come from the Enterprise COBOL manuals and the GnuCOBOL manual, and where the two differ the page says so.
A COBOL program has no declaration-time default: the storage of a data item holds whatever the runtime or the compiler puts there, unless the programmer says otherwise. Three features cover "otherwise", and they are the subject of this page:
-
the
VALUEclause gives a data item an initial value, or, on a level-88 entry, defines a condition-name; -
the
88level turns a value, a list of values or a range of values into a name that can be tested (IF BOOK-ACTIVE) and set (SET BOOK-ACTIVE TO TRUE); -
the
INITIALIZEstatement sets a whole record, or selected categories of its fields, to values at run time.
The layouts used are those of the Circulation library back office: BOOKREC, MEMBREC and LOANREC, whose level-88
entries (BOOK-ACTIVE, MEMBER-SUSPENDED, LOAN-CHECKOUT) are the flags the nightly run tests. How the data division is
organised and what the level numbers mean is covered in Data Division and Level Numbers;
the PIC and USAGE clauses that decide what a literal may be are in PICTURE Clause
and USAGE and Numeric Representation.
The VALUE clause on data items
In the WORKING-STORAGE SECTION and the LOCAL-STORAGE SECTION a VALUE clause gives a data item its initial contents
(Enterprise COBOL Language Reference, VALUE clause). The syntax of this format is only VALUE [IS] literal, where a figurative
constant (ZERO, SPACE, HIGH-VALUE, LOW-VALUE, QUOTE, ALL "ab") may replace the literal. Initialization is independent of
any BLANK WHEN ZERO or JUSTIFIED clause. The rules that matter in practice:
-
Class of the literal. A numeric item takes a numeric literal, aligned as in a numeric
MOVE(decimal point alignment), and the literal must not need truncation of nonzero digits. A literal with a sign needs a signedPICTURE(S). An alphanumeric, alphabetic, alphanumeric-edited or numeric-edited item described withUSAGE DISPLAYtakes an alphanumeric literal or a figurative constant, aligned left and padded with spaces, and it must not be longer than the item. -
Editing characters are counted. The functions of the editing characters in a
PICTUREare ignored when the initial value is determined, but they count towards the size. Enterprise COBOL’s own example is an itemPICTURE +999.99that must be givenVALUE "+012.34", the text exactly as it will be displayed. COBOL 2023 adds a numeric literal for numeric-edited items: the portable form is the alphanumeric literal, and GnuCOBOL 3.2 with-std=ibm -Wallwarns about the numeric literal (numeric literal in VALUE clause of numeric-edited item used [-Wdialect]). -
Groups.
VALUEmay be coded on a group item. The group area is initialized as one alphanumeric string, without regard to the subordinate items, and the subordinate entries then must not have aVALUEclause of their own. All subordinate items of an alphanumeric group must beUSAGE DISPLAY, none may beJUSTIFIEDorSYNCHRONIZED, and the literal must not be longer than the group. -
Tables. A
VALUEon an item that is, or is subordinate to, anOCCURSentry gives every occurrence the same value. Different values per occurrence need theFILLERplusREDEFINESidiom, described in Tables and OCCURS. A structure withOCCURS DEPENDING ONis initialized as if it had its maximum number of occurrences. -
Where it is not allowed. Not on an item that contains or is subordinate to an
EXTERNALorREDEFINESentry, not on an item that follows anOCCURS DEPENDING ONitem, and not on external floating-point items. The Language Reference describes the item-levelVALUEforWORKING-STORAGEandLOCAL-STORAGE; the contents of aFILE SECTIONorLINKAGE SECTIONitem come from the file or the caller.USAGE POINTERand the function and procedure pointers take onlyVALUE NULL(see Pointers and Dynamic Storage).
Example: VALUE on elementary items, groups and tables
The program shows counters starting at ZERO, VALUE ALL with a two-character pattern, a literal written on its own line, a group-level VALUE
whose subordinate items have none, a table built from FILLER items and REDEFINES, and a VALUE that applies to every occurrence. The last line displays items
copied from BOOKREC, which has no VALUE clauses at all.
IDENTIFICATION DIVISION.
PROGRAM-ID. VALUEDEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
COPY BOOKREC.
01 WS-COUNTERS.
05 WS-READ-COUNT PIC 9(5) VALUE ZERO.
05 WS-REJECT-COUNT PIC 9(5) VALUE ZERO.
05 WS-FINE-TOTAL PIC S9(7)V99 VALUE ZERO.
01 WS-BANNER PIC X(20) VALUE ALL "=-".
01 WS-RUN-TITLE PIC X(24)
VALUE "CIRCULATION NIGHTLY RUN".
01 WS-DEFAULT-LOAN-DAYS PIC 99 VALUE 14.
01 WS-DEFAULT-STATUS.
05 WS-DEF-CODE PIC X VALUE "A".
05 WS-DEF-NOTE PIC X(9) VALUE "NEW MEMBR".
01 WS-RUN-DATE VALUE "20261020".
05 WS-RUN-YEAR PIC 9(4).
05 WS-RUN-MONTH PIC 99.
05 WS-RUN-DAY PIC 99.
01 WS-DAY-NAMES.
05 FILLER PIC X(3) VALUE "MON".
05 FILLER PIC X(3) VALUE "TUE".
05 FILLER PIC X(3) VALUE "WED".
01 WS-DAY-TABLE REDEFINES WS-DAY-NAMES.
05 WS-DAY PIC X(3) OCCURS 3 TIMES.
01 WS-LIMITS.
05 WS-LIMIT PIC 9(2) OCCURS 3 TIMES VALUE 5.
PROCEDURE DIVISION.
MAIN-PARA.
DISPLAY WS-BANNER
DISPLAY WS-RUN-TITLE
DISPLAY "DAYS=" WS-DEFAULT-LOAN-DAYS
DISPLAY "DEF=" WS-DEFAULT-STATUS
DISPLAY "RUN DATE=" WS-RUN-YEAR "/" WS-RUN-MONTH "/"
WS-RUN-DAY
DISPLAY "DAY2=" WS-DAY (2)
DISPLAY "LIMITS=" WS-LIMITS
DISPLAY "COUNTERS=" WS-COUNTERS
DISPLAY "COPIES=" BOOK-COPIES " STATUS=[" BOOK-STATUS "]"
STOP RUN.
=-=-=-=-=-=-=-=-=-=-
CIRCULATION NIGHTLY RUN
DAYS=14
DEF=ANEW MEMBR
RUN DATE=2026/10/20
DAY2=TUE
LIMITS=050505
COUNTERS=0000000000000000000
COPIES=000 STATUS=[ ]
WS-BANNER repeats the pattern =- until the 20 bytes are full. WS-RUN-DATE is a group initialized by one literal, "20261020", which is
sliced into the year, month and day items below it, and which is why those items must not carry their own VALUE. WS-DEFAULT-STATUS is the
opposite arrangement, a group without a VALUE whose members each have one, so its display ANEW MEMBR is the two members one after the other.
WS-DAY (2) is TUE because the three three-letter FILLER items occupy nine contiguous bytes that REDEFINES reads as a table; and
LIMITS=050505 shows VALUE 5 applied to all three occurrences of WS-LIMIT.
Pitfalls, with the compiler’s own words
The next program is deliberately wrong. Each line shows one rule from the list above, and the diagnostics are the first line of
what cobc -x -Wall printed (the compiler also prints the source lines around each one):
IDENTIFICATION DIVISION.
PROGRAM-ID. BADSET.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-FOUND-SW PIC X VALUE "N".
88 RECORD-FOUND VALUE "Y".
01 WS-MODE PIC X VALUE "A".
88 MODE-ANY VALUE "A" "B" "C".
01 WS-COUNT PIC 9(3) VALUE "ABC".
01 WS-SHORT PIC X(3) VALUE "TOO LONG".
01 WS-AMT PIC 9(3) VALUE 1234.
01 WS-NEG PIC 9(3) VALUE -5.
PROCEDURE DIVISION.
MAIN-PARA.
SET RECORD-FOUND TO FALSE
SET MODE-ANY TO TRUE
DISPLAY WS-MODE
STOP RUN.
badset.cob:9: warning: numeric value is expected [-Wothers]
badset.cob:10: warning: value size exceeds data size [-Wothers]
badset.cob:10: note: value size is 8 [-Wothers]
badset.cob:11: warning: value size exceeds data size [-Wothers]
badset.cob:12: error: data item not signed
badset.cob: in paragraph 'MAIN-PARA':
badset.cob:15: error: field does not have a FALSE clause
The literal "ABC" in a numeric item and the over-long literals in WS-SHORT and WS-AMT are warnings, not errors: the compiler
truncates and carries on, so a run with a warning still writes a wrong initial value. The Enterprise COBOL manual states the
same rules without a "truncate and warn" outcome (the literal must not need truncation of nonzero digits and must not be longer than the
item), so treat every GnuCOBOL VALUE warning as an error in code that must also compile on z/OS. A negative literal in an unsigned item is a hard error (data item not signed), and SET RECORD-FOUND TO FALSE
needs a WHEN SET TO FALSE phrase (next sections).
A second set of mistakes concerns REDEFINES and OCCURS DEPENDING ON:
IDENTIFICATION DIVISION.
PROGRAM-ID. BAD2.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-SCORE PIC 9(3).
88 SCORE-BACKWARDS VALUE 100 THRU 50.
01 WS-RAW PIC X(3) VALUE "ABC".
01 WS-NUM REDEFINES WS-RAW PIC 9(3) VALUE 123.
01 WS-LIST-HOLDER.
05 WS-COUNT PIC 9.
05 WS-ITEM PIC X OCCURS 1 TO 5 TIMES
DEPENDING ON WS-COUNT.
05 WS-AFTER PIC X VALUE "X".
PROCEDURE DIVISION.
STOP RUN.
bad2.cob:8: warning: initial VALUE clause ignored for REDEFINES item 'WS-NUM' [-Winitial-value]
bad2.cob:11: error: 'WS-ITEM' cannot have OCCURS DEPENDING because of 'WS-AFTER'
A VALUE on WS-NUM is only a warning in GnuCOBOL and the value is ignored; the Enterprise COBOL manual does not allow it at all. A backwards range in a level-88 entry
(SCORE-BACKWARDS, below) produced no diagnostic at all. The OCCURS DEPENDING ON item cannot be followed by anything in the same
record, which also explains why a VALUE after one is rejected.
COBOL 2002 and later describe a VALUE per occurrence of a table. The Enterprise COBOL 6.5 manual refers to a "table format
VALUE clause" in its description of INITIALIZE, but the Language Reference’s VALUE clause page defines only the
data-item, condition-name and NULL formats, so this page does not give the syntax. GnuCOBOL 3.2.0 does not accept the form
OCCURS 3 TIMES VALUE 5 10 15:
tableval.cob:7: error: syntax error, unexpected .
5 | 01 WS-LIMITS.
6 | 05 WS-LIMIT PIC 9(2) OCCURS 3 TIMES
7 > VALUE 5 10 15.
8 | PROCEDURE DIVISION.
9 | DISPLAY WS-LIMITS
Use the FILLER/REDEFINES table or a loop (or INITIALIZE) instead.
What a data item holds when it has no VALUE
On z/OS the answer is in the manual: when no value is specified the contents are unpredictable (undefined), for both
WORKING-STORAGE and LOCAL-STORAGE items. A program must not read an item it has not set. INITIALIZE, a MOVE, a READ or
a VALUE clause are the ways to set it, and the compiler option INITCHECK (below) warns about the omissions it can see.
GnuCOBOL makes a choice that hides this class of bug. By default (-fdefaultbyte=init, the setting of the default dialect) every WORKING-STORAGE item without a VALUE is initialized according to its picture and usage, as if the compiler had
executed INITIALIZE ... ALL TO VALUE THEN TO DEFAULT on it: numeric items hold zero and alphanumeric items hold spaces. That is
why BOOK-COPIES shows 000 and BOOK-STATUS a space in the output above, although no VALUE clause was written. The option
-fdefaultbyte=value replaces that with one byte, written as a character in quotes or a decimal 0 to 255. With -fdefaultbyte=42
the same program printed COPIES=*** STATUS=[*]. The dialects differ: the configuration files for cobol85, cobol2002 and cobol2014 set defaultbyte to none ("initial storage is
undefined"), and with -std=cobol2014 the program printed NUL bytes for the status; with -std=ibm an alphanumeric item without a VALUE also
holds a NUL byte (STATUS=[ followed by the byte 00 and ]), where the default dialect holds a space. The manual lists the
value none for -fdefaultbyte; on the command line cobc 3.2.0 rejected it with unsupported value 'none' for configuration tag 'defaultbyte'.
The consequence for portable code: never rely on the default. Write VALUE on every flag and counter, as VALUEDEMO does, and
INITIALIZE every record before it is built field by field.
When is the initial state restored
Where an item lives decides how often its VALUE is applied (Enterprise COBOL Programming Guide, Comparison of WORKING-STORAGE and
LOCAL-STORAGE and Setting a program to an initial state):
| Storage | Allocated and initialized | Persists |
|---|---|---|
|
When the run unit starts. Items with a |
For the whole run unit, in the last-used state. Exceptions: a program with |
|
On every call or invocation. Items with a |
Freed on return. Each thread or recursive level has its own copy. |
|
|
Shared across programs of the run unit. |
The next source file contains a main program and two subprograms. COUNTER has one WORKING-STORAGE and one
LOCAL-STORAGE counter, both starting at zero; ICOUNT is declared IS INITIAL:
IDENTIFICATION DIVISION.
PROGRAM-ID. STORAGE.
PROCEDURE DIVISION.
MAIN-PARA.
CALL "COUNTER" CALL "COUNTER" CALL "COUNTER"
CALL "ICOUNT" CALL "ICOUNT"
STOP RUN.
END PROGRAM STORAGE.
IDENTIFICATION DIVISION.
PROGRAM-ID. COUNTER.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-CALLS PIC 9(3) VALUE ZERO.
LOCAL-STORAGE SECTION.
01 LS-CALLS PIC 9(3) VALUE ZERO.
PROCEDURE DIVISION.
ADD 1 TO WS-CALLS LS-CALLS
DISPLAY "COUNTER WS=" WS-CALLS " LS=" LS-CALLS
GOBACK.
END PROGRAM COUNTER.
IDENTIFICATION DIVISION.
PROGRAM-ID. ICOUNT IS INITIAL.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-CALLS PIC 9(3) VALUE ZERO.
PROCEDURE DIVISION.
ADD 1 TO WS-CALLS
DISPLAY "ICOUNT WS=" WS-CALLS
GOBACK.
END PROGRAM ICOUNT.
COUNTER WS=001 LS=001
COUNTER WS=002 LS=001
COUNTER WS=003 LS=001
ICOUNT WS=001
ICOUNT WS=001
Three calls to COUNTER count up in WS-CALLS (1, 2, 3) because the WORKING-STORAGE item remembers; LS-CALLS is 1 every time
because a fresh copy is made on each call. ICOUNT prints WS=001 twice, because IS INITIAL puts its WORKING-STORAGE back into
its initial state at every entry. The Enterprise COBOL manual adds that the INITIAL option has no effect on items without a
VALUE clause. Passing the same program through -std=ibm gave identical output. The mechanics of CALL and CANCEL are in
Subprograms, CALL and Linkage.
Level-88 condition-names
A condition-name is a level-88 entry that names the true values of the data item immediately above it, its conditional
variable. The entry has no PICTURE: it takes the characteristics of the conditional variable, it occupies no storage, and its
only clause is VALUE:
88 condition-name VALUE IS literal-1 [THROUGH literal-2] ...
[WHEN SET TO FALSE IS literal-3]
(VALUE or VALUES, IS or ARE, THRU or THROUGH are interchangeable, as Enterprise COBOL puts it.) The rules in Enterprise
COBOL’s Rules for condition-name entries:
-
The
VALUEclause is required and is the only clause of the entry. Level-88 entries must follow the conditional variable (or another 88 of the same variable) immediately. -
Each value can be a single literal, a list of literals separated by spaces (commas and semicolons are also separators), a range
literal-1 THRU literal-2whereliteral-1must be less thanliteral-2, or any mixture of these; the literal class must be one the conditional variable can be assigned. Ranges follow the collating sequence for alphanumeric data and are numeric for numeric items. -
The conditional variable may be any elementary item, or a group item, except another condition-name, a
RENAMES(level-66) item, aUSAGE INDEXitem, or an item withUSAGE POINTER,PROCEDURE-POINTER,FUNCTION-POINTERor object reference. For a group the literals must be alphanumeric and no longer than the group; no subordinate item may beJUSTIFIEDorSYNCHRONIZED. -
If the conditional variable is a table element, every reference to the condition-name needs the subscripts or indexes the variable needs.
-
A condition-name is tested like a condition:
IF MEMBER-ACTIVE. It is true when the variable equals any listed value or lies in any listed range, and false for every other value, including values that are not valid for the picture. -
The condition-name may be qualified like any data name (
LOAN-CHECKOUT OF LOAN-RECORD).
Example: lists, ranges, subscripts and qualification
The program uses the Circulation flags from the copybooks and adds a status/reason pair, a table of month lengths whose element has two
condition-names, a multi-condition SET and a qualified condition-name:
IDENTIFICATION DIVISION.
PROGRAM-ID. CIRC88.
DATA DIVISION.
WORKING-STORAGE SECTION.
COPY LOANREC.
COPY MEMBREC.
01 WS-RUN-FLAGS.
05 WS-VALID-SW PIC X VALUE "Y".
88 LOAN-VALID VALUE "Y".
88 LOAN-REJECTED VALUE "N".
05 WS-REASON PIC 99 VALUE ZERO.
88 NO-REASON VALUE ZERO.
88 BAD-MEMBER VALUE 1 THRU 9.
88 BAD-BOOK VALUE 10 THRU 19.
01 WS-MONTH-TABLE.
05 WS-MONTH-ENTRY OCCURS 3 TIMES.
10 WS-DAYS PIC 99 VALUE 31.
88 LONG-MONTH VALUE 31.
88 SHORT-MONTH VALUE 28 THRU 30.
PROCEDURE DIVISION.
MAIN-PARA.
MOVE "O" TO LOAN-TYPE
MOVE "S" TO MEMBER-STATUS
IF LOAN-CHECKOUT AND NOT MEMBER-ACTIVE
SET LOAN-REJECTED BAD-MEMBER TO TRUE
END-IF
DISPLAY "VALID=" WS-VALID-SW " REASON=" WS-REASON
IF BAD-MEMBER
DISPLAY "REJECT: MEMBER NOT ACTIVE"
END-IF
IF LOAN-CHECKOUT OF LOAN-RECORD
DISPLAY "QUALIFIED NAME TESTED"
END-IF
MOVE 30 TO WS-DAYS (2)
IF SHORT-MONTH (2) AND LONG-MONTH (1)
DISPLAY "MONTH 2 IS SHORT, MONTH 1 IS LONG"
END-IF
SET LONG-MONTH (2) TO TRUE
DISPLAY "MONTH 2 NOW " WS-DAYS (2)
SET LOAN-VALID NO-REASON TO TRUE
DISPLAY "VALID=" WS-VALID-SW " REASON=" WS-REASON
STOP RUN.
VALID=N REASON=01
REJECT: MEMBER NOT ACTIVE
QUALIFIED NAME TESTED
MONTH 2 IS SHORT, MONTH 1 IS LONG
MONTH 2 NOW 31
VALID=Y REASON=00
SET LOAN-REJECTED BAD-MEMBER TO TRUE is the same as two separate SET statements in the order given. BAD-MEMBER is the range 1 to 9
and SET stores its first value, 1, which is why REASON=01. LONG-MONTH (1) and SHORT-MONTH (2) are subscripted exactly like the
variable WS-DAYS.
Ranges, lists and the FALSE value
The next program tests a score range, a list of letters, a letter range, and the switch idiom with WHEN SET TO FALSE, and it also
changes the copybook’s MEMBER-STATUS through SET MEMBER-SUSPENDED TO TRUE:
IDENTIFICATION DIVISION.
PROGRAM-ID. CONDNAMES.
DATA DIVISION.
WORKING-STORAGE SECTION.
COPY MEMBREC.
01 WS-SCORE PIC 9(3).
88 SCORE-FAIL VALUE 0 THRU 49.
88 SCORE-PASS VALUE 50 THRU 100.
01 WS-CHAR PIC X.
88 CHAR-VOWEL VALUE "A" "E" "I" "O" "U".
88 CHAR-DIGIT VALUE "0" THRU "9".
01 WS-SWITCHES.
05 WS-EOF-SW PIC X VALUE "N".
88 END-OF-FILE VALUE "Y"
WHEN SET TO FALSE "N".
05 WS-FOUND-SW PIC X VALUE "N".
88 RECORD-FOUND VALUE "Y".
88 RECORD-MISSING VALUE "N".
PROCEDURE DIVISION.
MAIN-PARA.
MOVE "A" TO MEMBER-STATUS
IF MEMBER-ACTIVE
DISPLAY "ACTIVE: " MEMBER-STATUS
END-IF
SET MEMBER-SUSPENDED TO TRUE
DISPLAY "STATUS NOW: " MEMBER-STATUS
IF NOT MEMBER-ACTIVE
DISPLAY "NOT ACTIVE"
END-IF
MOVE 49 TO WS-SCORE
IF SCORE-FAIL DISPLAY "49 FAILS" END-IF
MOVE 50 TO WS-SCORE
IF SCORE-PASS DISPLAY "50 PASSES" END-IF
MOVE "E" TO WS-CHAR
IF CHAR-VOWEL DISPLAY "E IS A VOWEL" END-IF
MOVE "7" TO WS-CHAR
IF CHAR-DIGIT DISPLAY "7 IS A DIGIT" END-IF
SET END-OF-FILE TO TRUE
DISPLAY "EOF SWITCH: " WS-EOF-SW
SET END-OF-FILE TO FALSE
DISPLAY "EOF SWITCH: " WS-EOF-SW
SET RECORD-FOUND TO TRUE
DISPLAY "FOUND SWITCH: " WS-FOUND-SW
SET RECORD-MISSING TO TRUE
DISPLAY "FOUND SWITCH: " WS-FOUND-SW
STOP RUN.
ACTIVE: A
STATUS NOW: S
NOT ACTIVE
49 FAILS
50 PASSES
E IS A VOWEL
7 IS A DIGIT
EOF SWITCH: Y
EOF SWITCH: N
FOUND SWITCH: Y
FOUND SWITCH: N
The same output was produced with -std=ibm. END-OF-FILE was defined with VALUE "Y" WHEN SET TO FALSE "N", so SET END-OF-FILE TO FALSE
stores N. The WHEN SET TO FALSE literal is only the value SET ... TO FALSE stores, not the only value for which the condition is false:
testing END-OF-FILE is false for every value other than Y. The Enterprise COBOL syntax diagram writes it WHEN SET TO FALSE [IS] literal-3 (the manual’s sample code
spells it WHEN FALSE IS 99, which does not match the diagram); this page follows the diagram, and cobc 3.2.0 accepted it with and
without IS. A second flag, RECORD-FOUND and RECORD-MISSING, shows the alternative that needs no FALSE phrase: two names for the two values, each set with
SET ... TO TRUE.
A backwards range such as VALUE 100 THRU 50 is invalid in Enterprise COBOL (literal-1 must be less than literal-2). GnuCOBOL 3.2.0 compiled the program below with
-Wall and no diagnostic, and the condition was never true, not even for 100 and 50:
IDENTIFICATION DIVISION.
PROGRAM-ID. BACK.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-SCORE PIC 9(3).
88 SCORE-BACKWARDS VALUE 100 THRU 50.
PROCEDURE DIVISION.
MAIN-PARA.
PERFORM VARYING WS-SCORE FROM 40 BY 30 UNTIL WS-SCORE > 110
IF SCORE-BACKWARDS
DISPLAY WS-SCORE " TRUE"
ELSE
DISPLAY WS-SCORE " FALSE"
END-IF
END-PERFORM
STOP RUN.
040 FALSE
070 FALSE
100 FALSE
SET condition-name TO TRUE or FALSE
Format 4 of the SET statement moves a condition-name’s value to its conditional variable, following the rules of the VALUE clause
(Enterprise COBOL Language Reference, SET statement):
SET condition-name-1 [condition-name-2] ... TO TRUE SET condition-name-1 [condition-name-2] ... TO FALSE
-
TO TRUEstores the condition-name’s value. When there is a list or a range, the first literal is stored: the low end of aTHRUrange written first, the first literal of a list. Order the literals so that the one that should be set comes first. -
TO FALSErequires aWHEN SET TO FALSEphrase on the 88; without it the program does not compile (see the diagnostic above:field does not have a FALSE clause). -
Several condition-names in one
SETbehave as separateSETstatements, left to right. -
SET MEMBER-SUSPENDED TO TRUEis the safe way to change a status: the program never repeats the code"S", and a change of the stored value touches only the copybook. AMOVE "S" TO MEMBER-STATUScompiles whether or not"S"is a status that exists. -
SETdoes not test anything. It stores a value even if it contradicts other fields. The program that setsLOAN-REJECTEDis also responsible for clearingNO-REASON.
SET has other formats (indexes, pointers, ADDRESS OF, external switches); the table and pointer ones are in
Tables and OCCURS and Pointers and Dynamic Storage.
How a condition-name behaves inside IF, EVALUATE ... WHEN condition-name and with NOT is the subject of
Conditions, IF and EVALUATE.
INITIALIZE
INITIALIZE sets a record, a group or an elementary item to predetermined values. It is defined as "functionally equivalent to one or
more MOVE statements": it behaves as if one implicit MOVE were executed for every elementary item that qualifies, with the sending operand
SPACE or ZERO by default, according to the category. The general form (Enterprise COBOL Language Reference, INITIALIZE statement):
INITIALIZE identifier-1 [WITH FILLER]
[ {ALL | category-name} TO VALUE ]
[ THEN REPLACING {category-name DATA BY {identifier-2 | literal-1}} ... ]
[ THEN TO DEFAULT ]
with category-name one of ALPHABETIC, ALPHANUMERIC, ALPHANUMERIC-EDITED, DBCS, EGCS, NATIONAL, NATIONAL-EDITED, NUMERIC,
NUMERIC-EDITED or UTF-8. The receiving item is an alphanumeric, national or UTF-8 group, or an elementary item of a category the
statement can set, or a special register that is a valid MOVE receiver. A subscripted item may be named, but a whole table is initialized
only by naming the group that contains it. The item must not contain a RENAMES clause.
The rules for choosing the items that are set, applied in this order:
-
Always excluded: items that cannot be
MOVEreceivers; elementary items that areFILLER(explicit or implicit) unlessWITH FILLERis coded; items that are or sit under aREDEFINESorRENAMES. The named identifier may itself be redefined or inside a redefined area. -
Possible receivers: the named elementary item, or every elementary item in the named group, and for a table every occurrence.
-
Actually set: an item is set when at least one of these is true. The
VALUEphrase applies and the item’s category is covered and it has aVALUEclause. TheREPLACINGphrase names the item’s category.THEN TO DEFAULTis present. None ofVALUEandREPLACINGis coded.
The value stored is the VALUE clause literal for items chosen by VALUE, the REPLACING sender for items chosen by REPLACING, and otherwise
SPACE (alphabetic, alphanumeric, alphanumeric-edited, DBCS, national, national-edited, UTF-8) or ZERO (numeric, numeric-edited). A
category may appear only once in VALUE and once in REPLACING; ALL in the VALUE phrase stands for all categories at once.
Example: the INITIALIZE forms
The member record below has a numeric id, a name, a fine, a status flag, an unnamed FILLER that has a VALUE, and a trailing
note that has none. The program prints the whole group in brackets after every form so that the bytes can be compared. The
FILLER is two bytes at offset 24 (6 + 10 + 7 + 1 bytes before it), which the program fills with "XX" by reference modification to show
that WITH FILLER clears it.
IDENTIFICATION DIVISION.
PROGRAM-ID. INITDEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-MEMBER.
05 WS-M-ID PIC 9(6) VALUE 100.
05 WS-M-NAME PIC X(10) VALUE "ADA".
05 WS-M-FINES PIC 9(5)V99 VALUE 12.50.
05 WS-M-STATUS PIC X VALUE "A".
05 FILLER PIC X(2) VALUE "ZZ".
05 WS-M-NOTE PIC X(4).
PROCEDURE DIVISION.
MAIN-PARA.
MOVE "TEST" TO WS-M-NOTE
PERFORM SHOW-IT
INITIALIZE WS-MEMBER
DISPLAY "INITIALIZE"
PERFORM SHOW-IT
MOVE "XX" TO WS-MEMBER (24:2)
INITIALIZE WS-MEMBER WITH FILLER
DISPLAY "WITH FILLER"
PERFORM SHOW-IT
INITIALIZE WS-MEMBER
REPLACING ALPHANUMERIC DATA BY "?"
NUMERIC DATA BY 9
DISPLAY "REPLACING ALPHANUMERIC BY ?, NUMERIC BY 9"
PERFORM SHOW-IT
INITIALIZE WS-MEMBER ALL TO VALUE
DISPLAY "ALL TO VALUE"
PERFORM SHOW-IT
INITIALIZE WS-MEMBER
REPLACING NUMERIC DATA BY 5
THEN TO DEFAULT
DISPLAY "REPLACING NUMERIC BY 5 THEN TO DEFAULT"
PERFORM SHOW-IT
INITIALIZE WS-MEMBER ALL TO VALUE THEN TO DEFAULT
DISPLAY "ALL TO VALUE THEN TO DEFAULT"
PERFORM SHOW-IT
STOP RUN.
SHOW-IT.
DISPLAY " [" WS-MEMBER "]".
[000100ADA 0001250AZZTEST]
INITIALIZE
[000000 0000000 ZZ ]
WITH FILLER
[000000 0000000 ]
REPLACING ALPHANUMERIC BY ?, NUMERIC BY 9
[000009? 0000900? ? ]
ALL TO VALUE
[000100ADA 0001250A ? ]
REPLACING NUMERIC BY 5 THEN TO DEFAULT
[000005 0000500 ]
ALL TO VALUE THEN TO DEFAULT
[000100ADA 0001250A ]
Reading the lines:
| Form | Effect on the member record |
|---|---|
|
Numeric items to zero, alphanumeric items to spaces, |
|
As above, and the |
|
Only the named categories are set. The id becomes |
|
Items that have a |
|
The numeric items take 5. |
|
Every item with a |
The statement is "as if" a series of MOVE statements, so the usual MOVE rules apply to every implicit move: alignment of the numeric literal, truncation,
space padding of the alphanumeric literal. This also means that an item such as a COMP-3 field gets a valid packed zero, because the move is done per elementary item. The
statement cannot be applied to a variably located or variable-length item (a record after an OCCURS DEPENDING ON item).
What INITIALIZE skips: REDEFINES, tables, pointers
IDENTIFICATION DIVISION.
PROGRAM-ID. INITSHAPE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-AREA.
05 WS-N PIC 9(3) VALUE 5.
05 WS-A PIC X(3) VALUE "ABC".
05 WS-REDEF REDEFINES WS-A PIC 9(3).
05 WS-TAB OCCURS 3 TIMES.
10 WS-TN PIC 99 VALUE 7.
10 WS-TA PIC X VALUE "Z".
05 WS-I USAGE INDEX.
05 WS-P USAGE POINTER.
PROCEDURE DIVISION.
MAIN-PARA.
INITIALIZE WS-AREA
DISPLAY "[" WS-N "][" WS-A "][" WS-TAB (1) "]["
WS-TAB (3) "]"
IF WS-P = NULL
DISPLAY "POINTER IS NULL"
END-IF
MOVE "XYZ" TO WS-A
INITIALIZE WS-REDEF
DISPLAY "[" WS-A "]"
INITIALIZE WS-TAB (2)
STOP RUN.
[000][ ][00 ][00 ]
POINTER IS NULL
[000]
The group WS-AREA holds a number, a text with a REDEFINES view, a three-occurrence table and a pointer. INITIALIZE WS-AREA sets the
number to 000, the text to spaces and every occurrence of the table (WS-TAB (1) and WS-TAB (3) both show 00 and a space). The pointer
compares equal to NULL afterwards, but that is GnuCOBOL’s default initialization at work: the Enterprise COBOL manual lists no pointer or index category among the
receiving items of INITIALIZE, so a pointer is cleared with SET ... TO NULL and an index is set with SET. The redefining item WS-REDEF was skipped, because it is subordinate to a REDEFINES;
naming it directly (INITIALIZE WS-REDEF) is allowed, and then it set the bytes of WS-A to 000. The statement also works on a single subscripted occurrence (INITIALIZE WS-TAB (2)), and this
program ran with -std=ibm unchanged.
GnuCOBOL 3.2 deviation: the category before TO VALUE
Enterprise COBOL lets ALPHANUMERIC TO VALUE or NUMERIC TO VALUE restore only that category. GnuCOBOL 3.2.0 compiled the statements without warnings and
ignored the category: both forms restored every item that has a VALUE clause, as ALL TO VALUE does. The program changes both fields,
runs each form, and shows the whole group:
IDENTIFICATION DIVISION.
PROGRAM-ID. CATVALUE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-MEMBER.
05 WS-M-ID PIC 9(6) VALUE 100.
05 WS-M-NAME PIC X(10) VALUE "ADA".
PROCEDURE DIVISION.
MAIN-PARA.
MOVE 9 TO WS-M-ID
MOVE "CHANGED" TO WS-M-NAME
INITIALIZE WS-MEMBER ALPHANUMERIC TO VALUE
DISPLAY "[" WS-MEMBER "]"
MOVE 9 TO WS-M-ID
MOVE "CHANGED" TO WS-M-NAME
INITIALIZE WS-MEMBER NUMERIC TO VALUE
DISPLAY "[" WS-MEMBER "]"
STOP RUN.
[000100ADA ]
[000100ADA ]
Under Enterprise COBOL the first line would show the name restored and the id left as 000009, and the second the id restored and the name CHANGED.
Code that must behave the same on both compilers should use ALL TO VALUE or REPLACING, which behave as documented.
INITIALIZE or MOVE
-
INITIALIZE groupis the right way to blank a record before building it field by field: it knows each field’s category, so numeric fields get numeric zeros.MOVE SPACES TO groupleaves non-numeric spaces in numeric fields, so a later arithmetic statement on such a field is working on invalid data (see MOVE and Data Movement). -
INITIALIZEis a sequence of moves, one per elementary item. A one-time initial state for a large work area is better expressed withVALUEclauses. -
A
FILLERthat must hold a constant (theZZin the example) is lost byINITIALIZE WITH FILLERand not touched without it. Keep constants in named items, or restore them after aWITH FILLERinitialization.
The INITCHECK option (Enterprise COBOL; z/OS, not run here)
Enterprise COBOL 6.3 added the INITCHECK compiler option, which makes the compiler check at compile time for items used before they are initialized,
and issue warning messages. It is off by default (NOINITCHECK; abbreviations IC and NOIC), and INITCHECK alone means INITCHECK(LAX).
| Setting | Behaviour |
|---|---|
|
No warning for uninitialized items. |
|
Warn when an item is used with no initialization on any path to the statement. An item set on at least one path to the statement raises no warning. |
|
Warn unless the item is initialized on all paths to the statement. |
The manual’s own illustration has two items, Y and Z, with no VALUE. In Circulation terms (z/OS; not run here), with CBL INITCHECK(STRICT) on the first line:
CBL INITCHECK(STRICT)
IDENTIFICATION DIVISION.
PROGRAM-ID. FINECHK.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-FINE-LIMIT PIC 9(3).
01 WS-FINE-DUE PIC 9(3).
PROCEDURE DIVISION.
MAIN-PARA.
IF WS-FINE-LIMIT > 5
MOVE 2 TO WS-FINE-DUE
END-IF
DISPLAY WS-FINE-DUE
STOP RUN.
WS-FINE-LIMIT is read before any value is set, so both LAX and STRICT warn about it. WS-FINE-DUE is set on one path only: LAX stays quiet and
STRICT warns about the DISPLAY. The exact message numbers are not quoted here because the code was not run. The restrictions in the manual are worth knowing:
-
Only
WORKING-STORAGEandLOCAL-STORAGEitems are analysed; notLINKAGEorFILEitems, norEXTERNALorGLOBALitems. -
Table elements are not tracked individually: setting one element counts as setting all. Items set through a pointer (for example after
ADDRESS OF) can be reported wrongly, a reference-modified item counts as initialized, and only the first uninitialized item of a group is reported. -
Items passed
BY REFERENCEare not warned about;BY CONTENTandBY VALUEare. -
The analysis is purely at compile time and does not change the object program. It is more accurate with
OPTIMIZE(1)orOPTIMIZE(2)than withOPT(0), and may lengthen the compile.
GnuCOBOL 3.2.0 has no equivalent. The same two-item program compiled with cobc -x -Wall printed no diagnostic at all and displayed 000, because the default
-fdefaultbyte=init quietly provides the zero (see above). A COBOL test that passes under GnuCOBOL therefore does not show that an item is initialized on z/OS.
Where the book is outdated
The book consulted for this section (Taulli, Modern Mainframe Development, 2022) was written around Enterprise COBOL 6.3 and, as a survey of
the mainframe, treats the level numbers and the VALUE clause as basics; nothing is copied from it. It does not cover INITIALIZE or the SET
statement, and what it could not cover is below:
-
INITCHECKarrived with 6.3, the release the book calls the latest, and the Programming Guide for 6.5 is the place for its suboptions and restrictions; the rest of this page (VALUEwithWHEN SET TO FALSE, theINITIALIZEphrases) is not covered by the book as far as the section outline records. -
COBOL 2023 allows
VALUEfor numeric-edited items with a numeric literal, while the Enterprise COBOL 6.5 manual still describes the alphanumeric literal with every editing character spelt out; code that must compile on both uses the alphanumeric form. -
The book’s examples were written with GnuCOBOL (OpenCobolIDE), whose default of initializing every item hides uninitialized-data bugs that show up on z/OS, as demonstrated above.
References
-
Enterprise COBOL for z/OS 6.5 Language Reference: VALUE clause
-
Enterprise COBOL for z/OS 6.5 Language Reference: INITIALIZE statement
-
Enterprise COBOL for z/OS 6.5 Language Reference: SET statement
-
Enterprise COBOL for z/OS 6.5 Programming Guide: Comparison of WORKING-STORAGE and LOCAL-STORAGE
-
Modern Mainframe Development (Tom Taulli, O’Reilly Media, 2022), consulted as a narrative