Variables and Procedures in RPG IV
This chapter explores the fundamentals of defining constants, variables, and prototypes in RPG IV. These elements form the building blocks for structuring data and enabling modular code.
Defining Elements with D Specifications
In RPG IV, the Definition specification (commonly called a "D spec") is used to declare constants, variables, prototypes, and procedure interfaces. A D spec begins with DCL-x, where x is C for constants, S for standalone variables, DS for data structures, PR for prototypes, or PI for procedure interfaces. This is followed by the element's name, one or more keywords, and a semicolon to end the statement.
Keywords can generally appear in any order, but data-type keywords (e.g., CHAR or PACKED) must come first.
Defining Constants
Constants are the simplest declarations in RPG. Use DCL-C followed by the name and value. The CONST keyword is optional: dcl-c MAX_ELEMS 100; is equivalent to dcl-c MAX_ELEMS const(100);.
Create a new source member, paste the code below, compile it, and run it to display the constant values.
dcl-c default_city_name 'London';
dsply default_city_name;
Defining Standalone Fields
A standalone field (or scalar variable) is declared with DCL-S, followed by the name and data type. This creates a simple, single-value variable.
Example: Define an integer variable and use it in a loop.
dsply ('i = ' + %char(num));
endfor;
return;
Here, num is a 4-byte integer (10 digits total). The S in DCL-S denotes a standalone field.
Bonus Features:
- The FOR loop iterates from the start value to the end value.
- %CHAR converts numeric values to strings (e.g., "-12.345").
- The + operator concatenates strings alongside numeric operations.
Exercise:
- Declare a standalone character field of length 5 using the CHAR data type.
- Assign the value 'hello' to it.
- Display the field.
Your Exercise Answer should look something like this:
myCharField = 'hello';
dsply myCharField;
return;
Defining Data Structures
Data structures group related fields and are defined with DCL-DS followed by subfield declarations. End the structure with END-DS. For templates (using LIKEDS or LIKEREC), omit END-DS.
The INZ keyword initializes subfields. It works for standalone fields too.
Example: Define a qualified data structure and a linked copy.
name char(10) inz('Sam');
salary packed(9:2) inz(50000.25);
end-ds;
dcl-ds otherInfo likeds(info) inz(*likeds);
otherInfo.name = 'Joe';
otherInfo.salary += 10000;
dsply (otherInfo.name + ' has a salary of ' +
return;
Bonus Features:
- QUALIFIED requires referencing subfields as DS.SUBFIELD.
- LIKEDS copies the structure of the parent DS and auto-qualifies it.
- INZ(*LIKEDS) initializes the copy with the parent's values.
- += adds the right-hand value to the left-hand variable (like in C or Java).
Defining Arrays
RPG IV supports one-dimensional arrays via the DIM keyword. Access elements with (index). Simulate multi-dimensional arrays using nested data structure arrays (e.g., table(i).row(j).col(k)).
Scalar Array Example
Declare an array of dates and manipulate them.
dates(1) = %date(); // Current date
dates(2) = dates(1) + %days(1); // Tomorrow
dates(3) = dates(1) + %years(1); // Next year
dsply (%char(dates(1)) + ' ' + %char(dates(2)) + ' ' + %char(dates(3)));
return;
Bonus Features:
- DATE(*ISO) formats dates as yyyy-mm-dd.
- %DATE() returns the current date (no params) or converts strings/numerics to dates.
Data Structure Array Example
Define nested structures for families and people.
name varchar(25);
age packed(5);
end-ds;
dcl-ds families qualified dim(5);
address varchar(50);
numPeople uns(3);
people likeds(person) dim(8);
end-ds;
dcl-s i int(10);
families(1).people(1).name = 'Alice';
families(1).people(1).age = 3;
families(1).people(2).name = 'Bill';
families(1).people(2).age = 15;
families(1).numPeople = 2;
numFamilies = 1;
dsply (families(i).address);
for j = 1 to families(i).numPeople;
dsply (families(i).people(j).name + ' is ' +
endfor;
endfor;
return;
Bonus Features:
- VARCHAR creates variable-length strings (max length specified; prefixed by 2/4 bytes for current length). E.g., assigning "Alice" sets length to 5.
- LIKEDS on a subfield nests a data structure.
- UNS(5) (2-byte unsigned, up to 5 digits) and UNS(3) (1-byte unsigned, up to 3 digits).
Exercise
- Change the NAME subfield in person from VARCHAR(25) to CHAR(25).
- Recompile and run.
- Explain the output difference.
Answer
CHAR fields have fixed length, so they include trailing blanks in concatenations. VARCHAR trims them automatically. We can trim the CHAR statements using the built in function %TRIM
Defining Prototypes
Prototypes (DCL-PR ... END-PR) define calls to external programs, procedures, or Java methods. Always end with END-PR. Use EXTPGM for programs or EXTPROC for procedures (default if unspecified). The keyword specifies the target name.
Example 1: Calling a Program (QCMDEXC)
QCMDEXC executes system commands.
theCmd char(3000) const;
cmdLne packed(15:5) const;
dbcs char(3) const options(*nopass);
end-pr;
dcl-s cmd varchar(100);
qcmdexc (cmd : %len(cmd));
qcmdexc ('WRKSPLF' : 7);
return;
Bonus Features:
- EXTPGM names are case-sensitive (e.g., 'QCMDEXC' must match exactly).
- CONST prevents modification; allows literals/expressions and auto-temps for mismatches.
- Parameters use : separator in parentheses.
- %LEN returns the current length of varying strings.
Alternate (if prototype name matches program): Omit the name in EXTPGM—RPG uppercases it.
theCmd char(3000) const;
cmdLne packed(15:5) const;
dbcs char(3) const options(*nopass);
end-pr;
Example 2: Calling a Procedure (printf)
DSPLY limits output to 52 bytes and the external queue. Wrap C's printf in a subprocedure for better printing.
ctl-opt dftactgrp(*no) actgrp(*new);
/endif
dcl-s num int(10) inz(25);
return;
dcl-pi *n;
msg varchar(5000) const;
end-pi;
dcl-pr printf extproc(*dclcase);
template pointer value options(*string);
dummy int(10) value options(*nopass);
end-pr;
Bonus Features:
- Wrap printf in print for easier use (adds newline automatically).
- NEWLINE constant: Hex x'15'.
- *DCLCASE matches external name case (or specify EXTPROC('printf')).
- Dummy param with OPTIONS(*NOPASS) handles varargs.
- POINTER VALUE OPTIONS(*STRING): Passes null-terminated string (RPG adds terminator).
- /IF//ENDIF: Conditional compile for CRTBNDRPG (defines *CRTBNDRPG).
- CTL-OPT keywords:
- DFTActGRP(*NO): Required for bound calls.
- ACTGRP(*NEW): Sets activation group.
- OPTION(*SRCSTMT): Matches listing statement numbers to source.
