DIM(n) on a scalar subfield declares the classic in-DS array table: the subfield's n elements are contiguous bytes of the data structure rather than a separate array object. Element types character, packed, zoned, integer, unsigned and binary are supported; indexed element access and SORTA both work.
DCL-DS Totals;
Amt PACKED(7:2) DIM(4);
END-DS;
Amt(1) = 20.00;
Amt(2) = -7.00;
SORTA Amt; // Amt(1) is now -7.00
Because the elements are bytes of the structure, sorting them reorders those bytes in place - so an OVERLAY view of the same storage stays consistent with the sorted order.
SORTA collates by the element's own type: character elements order by their code page, while every numeric element type orders by numeric value. Those differ - as text, 100.00 sorts below 20.00, and a negative sorts below everything - so a numeric table sorts -7.00, 5.00, 20.00, 100.00. An UNS(20) table compares its elements as unsigned, so a value at or above 2^63 sorts last rather than first.
In a QUALIFIED structure the table is reached by its dotted path - the index follows the subfield name, not the structure name:
DCL-DS Q QUALIFIED;
Code CHAR(3) DIM(3);
END-DS;
Q.Code(1) = 'CCC';
Q.Code(2) = 'AAA';
SORTA Q.Code; // Q.Code(1) is now 'AAA'
The index may be a variable as well as a literal, and the qualified form supports every element type the unqualified form does. (Do not confuse Q.Code(i) with Q(i).Code - the latter indexes a DIM on the structure, selecting one element of a data-structure array.)
A subfield whose element type has no fixed byte image inside a data structure - an OBJECT reference - has no in-DS array representation and is rejected with TRN1058 rather than laid out at a guessed width.
LIKEDS may also appear on a subfield, making that subfield itself a data structure (a nested data structure). The nesting may continue to any depth, and each leaf is accessed by its full dotted path:
DCL-DS AddrT QUALIFIED TEMPLATE;
City CHAR(20);
State CHAR(2);
END-DS;
DCL-DS Person QUALIFIED;
Name CHAR(20);
Addr LIKEDS(AddrT); // subfield that is itself a data structure
END-DS;
Person.Name = 'John Smith';
Person.Addr.City = 'New York'; // leaf reached by full path
A LIKEDS subfield has no separate data type - its layout comes entirely from the named template - and the enclosing structure is treated as qualified.
LIKEDS may also be used on a procedure parameter, which receives a data
structure laid out like the template. Inside the procedure, the parameter's
subfields are read with dot notation:
DCL-PR ShowOrder;
ord LIKEDS(OrderTemplate) CONST;
END-PR;
DCL-PROC ShowOrder;
DCL-PI *N;
ord LIKEDS(OrderTemplate) CONST;
END-PI;
DSPLY ('qty=' + %CHAR(ord.Qty));
END-PROC;
A LIKEDS parameter may also be an array of data structures - add DIM(n) on
both the prototype and the interface. It is passed by reference (unless declared
VALUE/CONST), so a subfield the procedure writes through param(i).subfield
is visible in the caller's array after the call:
DCL-PR Bump;
lines LIKEDS(LineTemplate) DIM(10);
END-PR;
DCL-PROC Bump;
DCL-PI *N;
lines LIKEDS(LineTemplate) DIM(10);
END-PI;
lines(1).Qty = 999; // by reference - the caller sees this write
END-PROC;
A character array parameter (CHAR(n) DIM(m)) behaves the same way, and does so
across source formats - a fixed-format caller may pass its nA DIM(m) array
to a free-format char(n) dim(m) parameter and vice versa. The call links, and
an element the procedure writes is visible in the caller's array afterwards:
DBumpA PR EXTPROC('BUMPA')
D p 3A DIM(2)
Darr S 3A DIM(2)
C CALLP BumpA(arr) * arr(1) reflects the write
A procedure may also return a data structure by declaring its interface with
LIKEDS. The returned structure can be assigned to a compatible LIKEDS data
structure at the call site, copying every subfield:
DCL-PR ApplyPayment LIKEDS(applyResp);
req LIKEDS(applyReq) CONST;
END-PR;
DCL-PROC ApplyPayment;
DCL-PI *N LIKEDS(applyResp);
req LIKEDS(applyReq) CONST;
END-PI;
DCL-DS resp LIKEDS(applyResp);
resp.Message = 'Payment applied.';
RETURN resp;
END-PROC;
// Caller:
DCL-DS resp LIKEDS(applyResp);
resp = ApplyPayment(req);
DSPLY resp.Message; // Payment applied.
A procedure can also return an array, by carrying DIM on the prototype and
the interface. The caller receives it as an array and assigns it whole - that is
the only way RPG expresses it, since indexing a call result directly is not
valid syntax:
DCL-PR Build CHAR(5) DIM(3);
END-PR;
DCL-PROC Build;
DCL-PI *N CHAR(5) DIM(3);
END-PI;
DCL-S r CHAR(5) DIM(3);
r(1) = 'R1';
r(2) = 'R2';
r(3) = 'R3';
RETURN r;
END-PROC;
// Caller:
DCL-S Got CHAR(5) DIM(3);
Got = Build();
DSPLY Got(2); // R2
The same shape in fixed-format - DIM on the PR and on the PI, and the
caller assigning the whole array:
DBuild PR 5A DIM(3)
DGot S 5A DIM(3)
C EVAL Got = Build()
C Got(2) DSPLY
C SETON LR
PBuild B
DBuild PI 5A DIM(3)
Dr S 5A DIM(3)
C EVAL r(2) = 'R2'
C RETURN r
PBuild E
The element type may be character or numeric; a DIM return of either kind
hands back the whole array.