Data Structures
A data structure groups related fields under a single name. In other languages you’d call this a struct, a record, or a class with only data members. In RPG, it’s a dcl-ds.
You’ll use them constantly. Every record read from a file is effectively a data structure. Procedure return types with multiple values are data structures. Reusable field groupings — addresses, date ranges, order headers — are data structures.
Basic declaration
dcl-ds supplier qualified;
code char(10);
name varchar(50);
active ind;
onboard date;
end-ds;
Assign values using dot notation:
supplier.code = 'ACME001';
supplier.name = 'Acme Distributors';
supplier.active = *on;
supplier.onboard = %date();
dsply ('Supplier name: ' + %trim(supplier.name));
Why qualified
The qualified keyword forces dot notation (supplier.code instead of just code). Without it, subfield names become top-level names and you lose the encapsulation — worse, they can collide with other variables in your program.
Always use qualified. It costs nothing and prevents a whole class of bugs. Older RPG code you’ll encounter won’t use it; don’t mimic that in new code.
Templates with likeds
If you have a structure you want to declare multiple instances of, use likeds to reference the template:
dcl-ds supplierTemplate qualified template;
code char(10);
name varchar(50);
active ind;
onboard date;
end-ds;
dcl-ds primarySupplier likeds(supplierTemplate);
dcl-ds backupSupplier likeds(supplierTemplate);
The template keyword means supplierTemplate itself isn’t a variable — it’s just a shape. Only primarySupplier and backupSupplier are real, and they share the same structure.
Structures from database tables
You can declare a DS that matches a database table’s record format:
dcl-f SUPPLIER usage(*input);
dcl-ds supplierRec likerec(SP_REC);
Now supplierRec has fields matching the SP_REC record format — which, for our tables from Part 1 Chapter 6, means SP_SUPL, SP_NAME, SP_ACTIVE, SP_ONBOARD. When you read SUPPLIER into supplierRec;, the fields populate automatically.
This is one of the nicer integrations in RPG: the database schema and your code share a type system.
Arrays
Declare an array by adding a dimension:
dcl-s monthlySales packed(9:2) dim(12);
dcl-s regionCodes char(3) dim(50);
monthlySales(1) = 45000.00;
monthlySales(2) = 52300.00;
// ... etc
regionCodes(1) = 'NEU';
regionCodes(2) = 'AMS';
Indices start at 1, not 0. This trips up most developers coming from other languages. Budget for the mistake.
You can also have arrays of data structures:
dcl-ds orderLines qualified dim(100);
product char(15);
quantity packed(7:0);
unitPrice packed(9:2);
end-ds;
orderLines(1).product = 'WIDGET-STD-001';
orderLines(1).quantity = 5;
orderLines(1).unitPrice = 12.99;
When to reach for a DS
- Every time you’d otherwise pass 3+ related fields between procedures — wrap them
- Whenever you’re working with an entire database record — use
likerec - When you want a clean API for a return value with multiple components
- When you need an array of related data
The overhead of a DS vs. standalone variables is nothing. The readability gain is large. Err toward using them.
Next: Chapter 3: Procedures.