A prototype tells the compiler the signature of something it will call — a bound procedure or an external program — before any call to it is coded. A procedure interface does the matching job from the other side: it tells the compiler the signature of the procedure it is currently compiling. This page covers DCL-PR and DCL-PI syntax, the parameter keywords CONST, VALUE and OPTIONS, and the EXTPROC/EXTPGM calling-convention keywords, in free-form RPGLE.
This page is a lookup for prototype and interface syntax. For the module types a procedure lives in, see the RPGLE Modules and NOMAIN Reference. For building a service program end to end, see Build an ILE RPG Service Program. For binder-side signature rules, see the RPGLE Binder Language and Signatures Reference.
All examples are free-form RPGLE and are IBM DOC CHECKED or STATIC CHECKED against IBM’s ILE RPG Reference; none has been compiled in this workspace.
DCL-PR: declaring a prototype
dcl-pr prototype-name [return-type] [keywords];
parameter-name data-type [keywords];
end-pr [prototype-name];
A prototype starts with dcl-pr, the name, an optional return type and keywords, then one parameter definition per line, closed with end-pr. end-pr may repeat the prototype name; if the prototype has no parameters, end-pr can go on the dcl-pr line itself, after the keywords and before the semicolon — and in that position it cannot carry a name.
dcl-pr getCurrentUser char(10) end-pr;
A parameter whose name collides with a free-form opcode (such as select) needs the explicit dcl-parm keyword; any other parameter name may use it or omit it.
dcl-pr calcDiscount packed(7:2);
dcl-parm orderTotal packed(9:2) const;
custType char(1) const;
end-pr;
STATIC CHECKED. calcDiscount returns a packed value; orderTotal needs dcl-parm only because this page is being careful, not because orderTotal collides with an opcode — it is shown for the pattern, not because it is required here.
DCL-PI: declaring a procedure interface
dcl-pi {procedure-name | *n} [return-type] [keywords] [end-pi];
parameter-name data-type [keywords];
end-pi [procedure-name];
dcl-pi goes inside dcl-proc/end-proc and restates the procedure’s signature for the compiler. Use the procedure’s name when a separate dcl-pr prototype exists for it (the compiler checks the two against each other), or *n when the procedure has no separate prototype — common for the cycle-main or linear-main procedure of a program that nothing else calls as a bound procedure.
**free
dcl-pr calcDiscount packed(7:2);
orderTotal packed(9:2) const;
custType char(1) const;
end-pr;
dcl-proc calcDiscount;
dcl-pi calcDiscount;
orderTotal packed(9:2) const;
custType char(1) const;
end-pi;
dcl-s result packed(7:2);
if custType = 'P';
result = orderTotal * 0.10;
else;
result = orderTotal * 0.05;
endif;
return result;
end-proc;
STATIC CHECKED against IBM’s ILE RPG Reference for the DCL-PR/DCL-PI statement forms. The parameter lists in dcl-pr and dcl-pi must agree; IBM’s compiler enforces this match.
A no-parameter interface can also close on its own line, mirroring dcl-pr:
dcl-pi *n char(10) end-pi;
With no parameters, end-pi on this line cannot take a name either — the same rule as end-pr.
CONST: read-only reference parameters
CONST passes a parameter by reference but blocks the called procedure from changing it; the compiler rejects an assignment to a CONST parameter inside the procedure. Because the restriction is compile-time only inside that procedure, IBM notes two limits worth remembering: code outside the procedure, or a direct reference to the same global variable, can still change the underlying value, and the compiler may silently copy the argument into a temporary (with the prototype’s own data type and length) when the argument is an expression or a different format, then pass the temporary’s address instead of the original variable’s.
dcl-pr formatName varchar(60);
firstName varchar(30) const;
lastName varchar(30) const;
end-pr;
IBM DOC CHECKED (CONST keyword, Definition-Specification Keywords). CONST also has a second, unrelated role: on a standalone field or data structure (not a parameter), CONST without any parameter marks the item as a named constant whose value must be a literal, figurative constant, or built-in function.
VALUE: pass by value
VALUE marks a parameter as passed by value — the called procedure receives a copy, and nothing it does to that copy reaches the caller’s variable. IBM’s documented restriction: VALUE cannot be used on a parameter of a prototype defined with EXTPGM, because a program call always passes parameters by reference. VALUE is therefore only usable with a bound procedure call (EXTPROC, or no explicit calling-convention keyword).
dcl-pr refDouble int(10);
inNumber int(10) value;
end-pr;
IBM DOC CHECKED (VALUE keyword, Definition-Specification Keywords). IBM’s general compiler guidance, echoed by IBM’s own RPG team in community writing, is to prefer VALUE for pointers and small numeric parameters and CONST for arrays, data structures and strings, since VALUE copies the whole argument.
OPTIONS: parameter-passing flexibility
OPTIONS(value {: value ...}) combines one or more of the following documented values (IBM’s Definition-Specification Keywords, OPTIONS):
| Value | Effect |
|---|---|
*NOPASS | The caller is not required to pass this parameter. Every parameter after a *NOPASS one must also be *NOPASS. The procedure must check %PARMS before touching an unpassed parameter; the compiler does not check this for you |
*OMIT | The caller may pass the literal *OMIT instead of a value. Valid only for CONST parameters and parameters passed by reference. The procedure must test for it, such as with %ADDR(parm) <> *NULL |
*VARSIZE | For a by-reference character, graphic, UCS-2 or array parameter: the caller’s argument may be shorter or longer than the prototype length. The procedure must determine the actual length passed (a length parameter, operational descriptors, or %LEN) rather than assume the prototype’s size |
*EXACT | Enforces stricter matching between argument and prototype: for by-reference parameters, length, CCSID, array dimension, ASCEND/DESCEND and LIKEDS/LIKEREC/LIKE relationships must match exactly; for value or CONST parameters, data types must match and the argument’s length/decimal positions/integer positions must not exceed the prototype’s |
*STRING | For a basing pointer parameter passed by value or CONST: the caller may pass either a pointer or a character expression. An expression is copied to a temporary with a null terminator, and that temporary’s address is passed |
*TRIM | For a CONST or VALUE character, UCS-2 or graphic parameter: the argument is copied with leading and trailing blanks removed, as if %TRIM had been coded on every call |
*RIGHTADJ | For a CONST or VALUE character, graphic or UCS-2 parameter: the value is right-adjusted. Cannot be used on a varying-length prototype parameter, though a varying-length argument may still be passed to it |
*NULLIND | Passes the caller’s null-byte map alongside the parameter so the procedure can use %NULLIND on it. Requires ALWNULL(*USRCTL); not valid for VALUE parameters or parameters that also carry the NULLIND keyword; only *NOPASS/*OMIT may be combined with it |
dcl-pr logEvent extpgm('LOGEVT');
eventText varchar(200) const options(*varsize);
severity int(10) const options(*nopass);
end-pr;
IBM DOC CHECKED. eventText accepts shorter or longer arguments than 200 characters; severity is optional, and anything called through this prototype must check %PARMS before using severity if it was declared to be skipped.
EXTPROC and EXTPGM: what gets called
EXTPROC and EXTPGM tell the compiler how the call is resolved and are mutually exclusive on one prototype.
EXTPROC(name)resolves the call as a bound procedure call. Without anyEXTPROCorEXTPGMkeyword at all, IBM’s default for a prototyped procedure is the upper-case form of the RPG name.EXTPROC(*DCLCASE)uses the prototype’s own name, in the exact case it was written, as the external name. IBM i free-form definitions extend*DCLCASEtoEXPORTandIMPORTas well.EXTPGM(name)orEXTPGM('name')resolves the call as a dynamic program call — the same mechanism as the CLCALLcommand — and, per IBM’s documentation, forces parameters to pass by reference (noVALUEparameters allowed).
dcl-pr getCustomerCity char(30) extproc(*dclcase);
custNo char(8) const;
end-pr;
dcl-pr validateOrder ind extpgm('VALORD');
orderNo char(10) const;
end-pr;
IBM DOC CHECKED (EXTPROC keyword; “Specifying *DCLCASE as the External Name”). getCustomerCity is called as a bound procedure named exactly getCustomerCity; validateOrder is a dynamic program call to program VALORD, so every parameter on that prototype must be passed by reference.
Common mistakes
- Coding
VALUEon a parameter of anEXTPGMprototype. IBM documents this as not allowed, because program calls always pass by reference. - Relying on
*VARSIZEwithout actually checking the passed length inside the procedure — the keyword permits a shorter or longer argument, it does not tell the procedure how long the argument actually is. - Forgetting that
*NOPASSparameters must be trailing: once one parameter is*NOPASS, every parameter after it must be too. - Mismatching the parameter list between a prototype’s
DCL-PRand the matching procedure’sDCL-PI. The compiler checks this, but it is a common source of a compile-time error on first write. - Expecting
CONSTto make a parameter fully immutable everywhere. It blocks changes only inside the procedure that declared the parameter asCONST; the caller’s own code, or a global reference to the same variable, is unaffected. - Using
dcl-parmonly when a name collides with an opcode, then being surprised that other parameter names compile fine without it — the keyword is optional except in that one case.
FAQ
What is the difference between DCL-PR and DCL-PI?
DCL-PR prototypes something to be called — a separate procedure, or an external program. DCL-PI declares the interface of the procedure currently being written, so the compiler can check its signature, including against a matching DCL-PR if one exists.
When do I need a procedure interface without a prototype?
When the procedure is never called as a bound procedure from elsewhere in the same program — typically the cycle-main or linear-main procedure. Code dcl-pi *n with no name.
Can a parameter be both CONST and VALUE?
No. CONST passes by reference with a compile-time write restriction; VALUE passes a copy. They describe two different passing mechanisms and are not combined on one parameter.
Summary
DCL-PR ... END-PRprototypes a bound procedure or an external program;DCL-PI ... END-PIdeclares the interface of the procedure being compiled, and must match any corresponding prototype.CONSTpasses by reference with a compiler-enforced no-write rule inside the called procedure;VALUEpasses a copy and cannot be used withEXTPGM.OPTIONScombines values such as*NOPASS,*OMIT,*VARSIZE,*EXACT,*STRING,*TRIM,*RIGHTADJand*NULLIND, each with its own documented restrictions.EXTPROCresolves a bound procedure call (with*DCLCASEas a case-preserving option);EXTPGMresolves a dynamic program call and forces by-reference parameters.- Next: the RPGLE Modules and NOMAIN Reference for where these procedures live, and the RPGLE Binder Language and Signatures Reference for controlling what a service program exports.
Sources: Free-Form Prototype Definition, IBM i 7.5 ILE RPG Reference, Free-Form Procedure Interface Definition, IBM i 7.5 ILE RPG Reference, Definition of Prototyped Parameter, CONST keyword, VALUE keyword, OPTIONS keyword, EXTPROC keyword, Specifying *DCLCASE as the External Name.