RPGLE Passing Data by Value and by Reference

When you hand a variable to an RPGLE procedure, is the procedure working with your storage, or with a copy? The answer determines whether a change the procedure makes is still there when the call returns — and getting it wrong is one of the most common sources of “but I set that value, why is it still blank?” bugs in RPGLE code.

This tutorial answers that question precisely, for RPGLE specifically, using IBM’s own parameter-passing documentation rather than assumptions carried over from another language. You will see RPGLE’s default (reference-style) passing, the VALUE keyword, and the CONST keyword, each demonstrated with a before/after example that shows exactly what the caller sees after the call returns.

The starting point is RPGLE Variables and Storage Types, which introduced named, mutable storage, and RPGLE Data Structures Explained, which grouped related fields together. This article picks up where both left off: what happens to that storage the moment it crosses a procedure-call boundary.

Quick Summary

  • An argument is what the caller supplies at the call site. A parameter is the matching declaration in the called procedure that receives it.
  • RPGLE’s default is reference-style passing: a pointer to the data object goes into the parameter list, and a change the called procedure makes is reflected back in the caller.1
  • VALUE passes a copy. The called procedure can change its own copy freely, but the caller’s storage is untouched afterward.2
  • CONST prevents the called procedure from changing the parameter. It is not VALUE, and it is not a DCL-C named constant — three different things that share the word “constant” in casual conversation but not in the language.3
  • A data structure follows the same reference/VALUE rules as a scalar — this article reuses TEMPLATE and LIKEDS from RPGLE Data Structures Explained without re-teaching them.
  • Choosing reference, VALUE, or CONST for a given parameter is an editorial judgment call layered on top of verified behavior, not an IBM requirement.

What Gets Passed to a Procedure?

Every one of the examples in this article answers one question three different ways: when a variable is handed to a procedure call, does the procedure end up working with the caller’s actual storage, or with a copy? The rest of this article works through that question for RPGLE’s default behavior, VALUE, and CONST, then applies the same question to a data structure instead of a plain scalar.

Reader Prerequisites

This article assumes you can already declare a variable with DCL-S and understand scope and storage duration, from RPGLE Variables and Storage Types. It also assumes you can read a DCL-DS declaration built with QUALIFIED, TEMPLATE, and LIKEDS, from RPGLE Data Structures Explained — this article reuses that mechanics without re-explaining it. Finally, it assumes the variable/constant/literal vocabulary from RPGLE Constants and Literals, because CONST on a parameter and DCL-C are easy to confuse and this article draws that line explicitly.

No knowledge of writing a prototype or procedure interface is required. Every example uses a minimal, already-correct DCL-PR/DCL-PI pair; designing one from scratch, matching signatures, and keeping PR/PI definitions synchronized is a distinct skill reserved for a later lesson on prototypes and procedure interfaces.

Learning Outcomes

After working through this tutorial, you should be able to:

  1. Distinguish an argument from a parameter in RPGLE terms.
  2. State what RPGLE’s default parameter passing does to caller storage, and predict whether a change is visible after a call.
  3. Explain what VALUE copies, and why the caller is unaffected by what the called procedure does with its copy.
  4. Explain what CONST protects against, and why it is not the same as VALUE or the same as a DCL-C named constant.
  5. Read a before/after example and correctly predict the caller’s value after each of the three passing modes.
  6. Recognize that a data structure passed as a parameter follows the same reference/VALUE rules as a scalar.
  7. Choose a passing mode for a given scenario, understanding that the choice is editorial guidance, not a compiler rule.

Argument vs Parameter

An argument is the value or variable the caller supplies at the call site. A parameter is the matching declaration in the called procedure’s interface that receives it. The two line up positionally — the first argument binds to the first parameter, and so on.

dcl-pr bumpQuantity;
  quantity int(10);
end-pr;
bumpQuantity(quantity);

In the call bumpQuantity(quantity), the caller’s quantity variable is the argument. Inside bumpQuantity, the quantity parameter declared on the prototype is what receives it. They can share a name, as they do here, or not — the names are independent; only the position and type matter for the match.

Every example in this article shows a minimal prototype (DCL-PR) and, where a procedure body is shown, a matching procedure interface (DCL-PI) — just enough to make the parameter-passing behavior concrete. Designing a prototype, choosing its parameter list, and keeping a DCL-PR and DCL-PI in sync is its own skill, covered in a dedicated lesson on prototypes and procedure interfaces; this article does not teach it.

Pass by Reference (Default)

RPGLE parameters are passed by reference by default — this is documented as the standard convention for RPG (alongside CL and COBOL). Reference passing means a pointer to the data object is placed into the parameter list, so the called procedure and the caller are working with the same underlying storage; a change the called procedure makes to the parameter is reflected back in the calling program.1

dcl-pr bumpQuantity;
  quantity int(10);
end-pr;

dcl-s quantity int(10);
dcl-s displayLine varchar(40);

quantity = 5;
displayLine = 'before=' + %char(quantity);
dsply displayLine;

bumpQuantity(quantity);

displayLine = 'after=' + %char(quantity);
dsply displayLine;
dcl-proc bumpQuantity;
  dcl-pi *n;
    quantity int(10);
  end-pi;

  quantity += 1;
end-proc;

Nothing on the quantity parameter requests a different behavior, so this is ordinary default passing. bumpQuantity increments its quantity parameter, and because that parameter refers to the caller’s own storage, the caller’s quantity shows the change: before=5, then after=6.

This is what “reference” means here, in RPGLE’s own documented terms — a pointer to the caller’s data placed into the parameter list — not a claim borrowed from what “reference” means in Java, Python, or C++. Whether that pointer surfaces as source-level syntax you write yourself is a separate question from whether the underlying passing mechanism is reference-style; this article does not need pointer syntax to demonstrate the behavior.

Pass by Value with VALUE

The VALUE keyword requests the opposite: “the VALUE keyword indicates that the parameter is passed by value rather than by reference.”2 The called procedure receives its own copy, so changes it makes to that copy have no effect on the caller’s storage.

dcl-pr bumpQuantityByValue;
  quantity int(10) value;
end-pr;

dcl-s quantity int(10);
dcl-s displayLine varchar(40);

quantity = 5;
displayLine = 'before=' + %char(quantity);
dsply displayLine;

bumpQuantityByValue(quantity);

displayLine = 'after=' + %char(quantity);
dsply displayLine;
dcl-proc bumpQuantityByValue;
  dcl-pi *n;
    quantity int(10) value;
  end-pi;

  dcl-s displayLine varchar(40);

  quantity += 1;
  displayLine = 'inside=' + %char(quantity);
  dsply displayLine;
end-proc;

Running this in order, the display lines read before=5, inside=6, after=5. Inside bumpQuantityByValue, quantity really did become 6 — that is the callee’s own copy, and it changed correctly. But the caller’s quantity, checked after the call returns, is still 5. The caller was never connected to the callee’s copy in the first place.

Two restrictions are worth knowing. VALUE cannot be used on a parameter whose prototype was defined with EXTPGM, because “calls to programs require that parameters be passed by reference” — VALUE is a procedure-call mechanism, not a program-call one.2 And what is allowed as a value-parameter argument follows the same compatibility rules as an EVAL assignment: “the parameter received by the procedure corresponds to the left-hand side of the expression; the passed parameter corresponds to the right-hand side.”2 In practice, that means you can pass a compatible expression, not only a bare variable, to a VALUE parameter.

Read-Only Parameters with CONST

CONST is a third option, and it answers a different question than VALUE does. Where VALUE asks “should the caller be isolated from any change,” CONST asks “should the callee be allowed to change this at all.” IBM documents that “a CONST parameter cannot be changed by statements within the procedure.”3

dcl-pr describeQuantity;
  quantity int(10) const;
end-pr;

// A DCL-C named constant is a different mechanism (ARTICLE-062), not a
// parameter-passing keyword. It is never assumed equivalent to CONST here.
dcl-c DefaultQuantity const(5);

dcl-s quantity int(10);

quantity = 5;
describeQuantity(quantity);

// CONST also accepts an expression argument, not just a variable.
describeQuantity(quantity + 1);

// A DCL-C named constant can be passed too; it is a value like any other.
describeQuantity(DefaultQuantity);
dcl-proc describeQuantity;
  dcl-pi *n;
    quantity int(10) const;
  end-pi;

  dcl-s displayLine varchar(40);

  // quantity is read-only here. IBM documents that a CONST parameter
  // cannot be changed by statements within the procedure; the line
  // below is commented out because it would fail to compile:
  // quantity += 1;

  displayLine = 'received=' + %char(quantity);
  dsply displayLine;
end-proc;

Three calls, three different kinds of argument — a plain variable, an arithmetic expression, and a DCL-C named constant — and all three are accepted, because CONST allows arguments that ordinary reference passing does not. IBM documents why: to support that flexibility, “the compiler may copy the parameter to a temporary defined with the same data type and length as the prototyped parameter and pass the address of the temporary,” specifically when the passed argument is an expression, or has a different format than the prototyped parameter.3 That is a documented compiler mechanism for making CONST more flexible to call, not a general promise that every CONST parameter is copy-isolated the way a VALUE parameter is.

CONST is not VALUE. VALUE isolates the caller from any change, by design. CONST prevents the callee from changing the parameter at all — it never gets the chance, so isolation is not the point. IBM’s own caution reflects this: “do not use this keyword on a prototype definition unless you are sure that the parameter will not be changed by the called program or procedure.”3 That caution is about correctness of intent, not about CONST silently behaving like VALUE.

CONST is not DCL-C. A DCL-C named constant, covered in RPGLE Constants and Literals, is a compile-time named value with no storage of its own. CONST on a parameter is a call-time restriction on an ordinary storage location. The third call above, describeQuantity(DefaultQuantity), shows them meeting at the call site: DefaultQuantity is passed as an ordinary value, exactly like any other argument — it is not what makes the quantity parameter read-only. The CONST keyword on the parameter does that.

Side-by-Side Comparison

ModeKeyword / defaultCaller storage shared?Callee can modify?Caller sees change?Typical useCaution
Reference (default)No keywordYes — a pointer to the caller’s dataYesYesThe callee is meant to modify the caller’s data (an output or in/out parameter)Any unintentional modification is visible to the caller1
VALUEvalueNo — callee receives a copyYes, its own copyNoThe caller must be isolated from whatever the callee doesCannot be used with EXTPGM-defined prototypes; argument must be EVAL-assignment compatible2
CONSTconstNot guaranteed isolated — may be the original or a compiler-created temporaryNo — protected by the compilerNot applicable (unchanged)The callee only needs to read the value, and the argument may be an expression or a differently formatted valueNot the same as VALUE‘s isolation guarantee; not the same as a DCL-C named constant3

Worked Example: Caller Before and After

Put the three modes side by side and the pattern is direct: only reference passing lets the callee’s change reach the caller.

ModeCaller before the callWhat the callee doesCaller after the call
Reference (default)quantity = 5quantity += 1; on its parameterquantity = 6
VALUEquantity = 5quantity += 1; on its own copy (becomes 6 inside the callee)quantity = 5
CONSTquantity = 5Reads quantity; cannot change it (quantity += 1; would not compile)quantity = 5 (never modified)
Caller variable quantity equals 5 flows two ways into a called procedure. Passed by reference, the default, the callee works with the caller's own storage and the caller sees quantity equal 6 after the call. Passed by VALUE, the callee receives a copy and the caller's quantity remains 5 after the call.
A conceptual data-flow contrast, not a memory-address or byte-level diagram.

The VALUE and CONST rows end at the same caller-visible value, 5, but for different reasons: VALUE‘s callee changed a copy that was never connected back to the caller; CONST‘s callee was never permitted to change anything in the first place. Predicting the right row for a given passing mode is the entire point of this article.

Passing a Data Structure

A data structure passed as a parameter follows the same reference/VALUE rules as a scalar. This example reuses TEMPLATE and LIKEDS exactly as RPGLE Data Structures Explained documents them; nothing about declaring a data structure is taught again here.

dcl-ds OrderLine_t qualified template;
  quantity int(10);
  lineTotal packed(9:2);
end-ds;

dcl-pr adjustLineByReference;
  line likeds(OrderLine_t);
end-pr;

dcl-pr adjustLineByValue;
  line likeds(OrderLine_t) value;
end-pr;

dcl-ds orderLine likeds(OrderLine_t);
dcl-s displayLine varchar(40);

orderLine.quantity = 5;
orderLine.lineTotal = 49.95;

displayLine = 'before=' + %char(orderLine.quantity);
dsply displayLine;

adjustLineByReference(orderLine);
displayLine = 'after-reference=' + %char(orderLine.quantity);
dsply displayLine;

orderLine.quantity = 5;

adjustLineByValue(orderLine);
displayLine = 'after-value=' + %char(orderLine.quantity);
dsply displayLine;
dcl-proc adjustLineByReference;
  dcl-pi *n;
    line likeds(OrderLine_t);
  end-pi;

  line.quantity += 1;
end-proc;

dcl-proc adjustLineByValue;
  dcl-pi *n;
    line likeds(OrderLine_t) value;
  end-pi;

  line.quantity += 1;
end-proc;

The output is before=5, after-reference=6, then, after the caller resets orderLine.quantity back to 5, after-value=5. adjustLineByReference modifies the caller’s own orderLine structure — the change is visible. adjustLineByValue modifies a copy of the whole structure — the caller’s orderLine is untouched. The subfield being changed happens to be quantity, but nothing about this behavior is specific to data structures; it is the same reference-versus-VALUE rule already shown for a plain scalar, applied to a structure instead.

Relevant OPTIONS Keywords

RPGLE also has an OPTIONS keyword family for parameters, with forms including *NOPASS (an optional trailing parameter that need not be passed at all) and *OMIT (a parameter that can be replaced with the special value *OMIT at the call site). Both exist to let a procedure accept a variable-length argument list, which is a parameter-list design decision.

This article does not teach their exact mechanics. A good-faith attempt to confirm the current IBM i 7.4/7.5 reference wording for *NOPASS, *OMIT, and *VARSIZE did not return primary source text — only documentation index pages. Rather than teach those forms from secondary tutorials, this article names them as existing and defers their exact rules to the dedicated lesson on prototypes and procedure interfaces, where parameter-list design belongs. If you need OPTIONS today, verify its exact current-release behavior directly against IBM’s ILE RPG Language Reference before relying on it.

Choosing the Right Mode

The following guidance is editorial, not an IBM requirement. IBM does not mandate reference, VALUE, or CONST for any particular parameter; the compiler accepts whichever one you choose as long as it is used correctly.

ScenarioRecommended modeRationaleCaution
Input-only scalar, read but never changedCONSTDocuments intent, protects against accidental modification, and accepts expressions as argumentsDo not assume VALUE-equivalent isolation from a temporary copy
Modifiable scalar, caller expects the changeReference (default)This is what reference passing is for — no extra keyword neededAny unintentional change inside the procedure is visible to the caller
Input-only data structureCONSTSame read-only intent as a scalar, applied to a structureConfirm the structure is not accidentally modified deep in the procedure
Caller-owned result/output parameterReference (default)The whole purpose is for the caller to see the value the procedure producesDocument clearly that the parameter is an output, since nothing in the call syntax marks it that way
Editorial decision guidance: starting from a caller-owned value, ask whether the callee should modify it. Yes leads to reference, the default. No, with isolation wanted, leads to VALUE. No, but the callee still needs to read it, leads to CONST.
Editorial decision guidance, not an IBM compiler rule.

Common Mistakes

Expecting a VALUE parameter’s changes to reach the caller. VALUE isolates the caller by design. If a value seems to silently “reset” after a call, check whether the parameter was declared VALUE.

Accidentally modifying reference-passed data. Because reference is the default, a plain scalar or structure parameter with no keyword is modifiable by the callee whether that was intended or not. If a parameter should be read-only, say so with CONST.

Treating CONST as identical to VALUE. CONST protects against modification; it does not promise the same caller isolation that VALUE documents. They solve different problems.

Confusing CONST with a DCL-C named constant. A DCL-C value is a compile-time named literal with no storage. CONST on a parameter is a call-time restriction on an ordinary storage location. CONST and DCL-C can appear in the same line of code (as in describeQuantity(DefaultQuantity) above) without being the same mechanism.

Assuming another language’s defaults apply. RPGLE’s default is reference-style passing. Do not assume it matches whatever “pass by value” or “pass by reference” means by default in a language you already know.

Misreading what “the caller sees a change” means for a data structure. The same reference-versus-VALUE distinction that applies to a scalar applies to a whole structure passed as a parameter — there is no separate rule to learn for structures.

FAQ

What is the difference between an argument and a parameter in RPGLE?

An argument is what the caller supplies at the call site. A parameter is the matching declaration in the called procedure’s interface that receives it. They correspond by position, not by name.

Does RPGLE pass parameters by reference or by value by default?

By reference. A pointer to the data object is placed into the parameter list, and a change the called procedure makes is reflected back in the caller, unless a parameter is explicitly declared VALUE.1

What does the VALUE keyword actually copy, and can the caller see changes afterward?

VALUE passes a copy of the argument. The called procedure can change that copy freely, but the caller’s own storage is unaffected — the two were never connected.2

What does CONST protect against, and does it guarantee the same isolation as VALUE?

CONST prevents the called procedure from changing the parameter. It does not guarantee VALUE-style isolation from the caller’s own storage; IBM documents that the compiler may create a temporary copy only under specific conditions, such as an expression argument.3

Is a CONST parameter the same thing as a DCL-C named constant?

No. A DCL-C named constant is a compile-time name bound to a literal value, with no storage of its own — covered in RPGLE Constants and Literals. CONST on a parameter is a restriction on an ordinary storage location that is passed at call time. A DCL-C value can itself be passed as an ordinary argument to a CONST parameter, without the two mechanisms being the same thing.

What happens when I pass a data structure as a parameter instead of a scalar?

The same reference/VALUE rules apply. Passed by reference, the callee works with the caller’s own structure and a change is visible afterward. Passed by VALUE, the callee works with a copy and the caller’s structure is unchanged.

Where can I learn about OPTIONS(NOPASS), OPTIONS(OMIT), and optional parameters?

This article names them but does not teach their exact mechanics, because direct confirmation against the current IBM i reference could not be obtained for this draft. Parameter-list design, including optional parameters, belongs to the dedicated lesson on prototypes and procedure interfaces.

How do I decide whether a parameter should be reference, VALUE, or CONST?

Use reference when the caller expects the procedure to modify its data. Use VALUE when the caller should be fully isolated from whatever the procedure does. Use CONST when the procedure only needs to read the value. This is editorial guidance, not a compiler requirement — see the Choosing the Right Mode section above.

Key Takeaways

  • An argument is supplied by the caller; a parameter receives it in the called procedure, matched by position.
  • RPGLE’s default is reference passing: the callee shares the caller’s storage, and a change is visible after the call.
  • VALUE passes a copy; the caller is isolated from anything the callee does to it.
  • CONST prevents modification by the callee but does not promise VALUE-style isolation, and it is not the same mechanism as a DCL-C named constant.
  • A data structure parameter follows the exact same reference/VALUE rules as a scalar.
  • Choosing a passing mode is a deliberate editorial decision about intent, not something the compiler dictates.

Continue Your Learning

  1. Foundation: RPGLE Variables and Storage Types
  2. Required: RPGLE Data Structures Explained
  3. Related: RPGLE Constants and Literals
  4. Current: RPGLE Passing Data by Value and by Reference
  5. Planned next: RPGLE IF, ELSE, and ELSEIF Decisions (ARTICLE-064)
  6. Then planned: RPGLE Select and When Logic (ARTICLE-065)
  7. Related design lesson: RPGLE Prototypes and Procedure Interfaces (ARTICLE-077), which covers DCL-PR/DCL-PI design and OPTIONS in full
  8. Learning-path overview: RPGLE for Beginners: A Practical IBM i Learning Path

Upcoming lessons are named without links because their public destinations have not been established for this draft. ARTICLE-077 covers how to design a prototype and procedure interface, including full OPTIONS coverage; this article used only a minimal, already-correct pair to demonstrate parameter-passing behavior.

IBM Evidence Used

The technical claims in this article are drawn from three IBM i 7.5 documentation pages, each fetched directly and confirmed to return substantive section content rather than a documentation index: “Passing Parameters” for the default reference-passing convention and its exact definition; the “VALUE Keyword” page for VALUE‘s purpose, its EXTPGM restriction, and its EVAL-assignment-compatibility rule; and the “CONST Keyword” page for CONST‘s modification protection, its documented temporary-copy conditions, and its own caution about intended use.

OPTIONS(*NOPASS), OPTIONS(*OMIT), and OPTIONS(*VARSIZE) were investigated with the same method. Every attempted URL for those specific pages returned only documentation index content, not target section text. That gap is reported directly in the Relevant OPTIONS Keywords section above rather than filled from secondary tutorials.

The four code assets are original teaching material checked against the rules above. They have not been compiled or run on IBM i in this workspace; expected observations require an IBM i verification pass. The code README records the source-access details and claim map, including the exact reference pages used.

References


  1. IBM, “Passing Parameters,” IBM i 7.5 documentation. ↩↩↩↩

  2. IBM, “VALUE Keyword,” IBM i 7.5 ILE RPG Reference. ↩↩↩↩↩↩

  3. IBM, “CONST Keyword,” IBM i 7.5 ILE RPG Reference. ↩↩↩↩↩↩

References

  1. Passing Parameters — IBM
  2. VALUE Keyword — IBM
  3. CONST Keyword — IBM



Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top