Excellent question! Let's clarify the difference between *INLR
and RETURN
in RPG, and why you often need to use both together — especially in modular ILE RPGLE programs.
โ Quick Summary
Term | Purpose | When It Happens |
---|---|---|
*INLR |
Tells the system to "end program and release resources" | Runtime flag to clean up program |
RETURN |
Actually exits the program or procedure | Execution control ends current scope |
๐ง What Each Does
1. *INLR = *ON
-
LR = Last Record (historical term)
-
Signals that:
-
Files can be closed
-
Resources can be released
-
Static storage is freed
-
-
Applies only at the end of a module, not a subprocedure
-
Has no effect by itself unless followed by
RETURN
2. RETURN
-
Exits the current program or subprocedure
-
Without
*INLR = *ON
, it leaves the program resident in memory -
Used alone in ILE means:
-
Files stay open
-
Static variables keep their values
-
Memory is not cleaned up
-
๐ฅ Why You Need Both Together
*inlr = *on;
return;
This combination:
-
โ Closes all files
-
โ Releases all memory used by the program
-
โ Exits cleanly
If you do only one:
๐ธ return
only:
-
Program stays resident
-
Next call to the program shares the same ODP, variables, file pointers
-
Can cause bugs like:
-
READ
returns wrong record -
Files appear already open
-
Static variables keep old values
-
๐ธ *inlr = *on
only:
-
Does nothing unless followed by
return
or program naturally ends
๐งช Example
dcl-f SALESF usage(*input);
dcl-s counter int(5) static;
// Reads first record and keeps file open
read SALESF;
counter += 1;
dsply ('Counter = ' + %char(counter));
// Cleanup
*inlr = *on;
return;
If you omit *INLR = *ON
, next time you call the program:
-
It starts at record 2 (not 1)
-
counter
starts from previous value
๐ Best Practices
When | Use |
---|---|
End of main RPGLE program | *inlr = *on; return; |
Subprocedure | Just return; (no *INLR needed) |
Service program | No *INLR ; keep memory alive |
Batch job | Always use both to ensure cleanup |
Let’s build a code demo that clearly shows the impact of using (or not using) *INLR = *ON
in an RPGLE program — specifically how it affects:
-
File pointer (ODP)
-
Static variables
๐งพ Demo Setup: File SALESF
A R SALESREC
A SALEID 5A
A AMOUNT 9P 2
A K SALEID
Sample data:
SALEID | AMOUNT |
---|---|
S001 | 100.00 |
S002 | 200.00 |
S003 | 300.00 |
๐งพ Program: SALESDEMO
ctl-opt dftactgrp(*no) actgrp(*caller);
dcl-f SALESF usage(*input);
dcl-s counter int(5) static;
read SALESF;
if not %eof(SALESF);
counter += 1;
dsply ('READ SALEID: ' + SALEID);
dsply ('COUNTER VALUE: ' + %char(counter));
else;
dsply 'EOF';
endif;
// Optional cleanup โ comment/uncomment to test effect
*inlr = *on;
return;
๐งช Test Procedure
-
Run
CALL SALESDEMO
multiple times, commenting or uncommenting the*INLR = *ON
line. -
Observe the difference in:
-
What record is read
-
What value
counter
holds
-
๐ Scenario A: Without *INLR = *ON
// *inlr = *on; <--- commented out
return;
Run 1:
READ SALEID: S001
COUNTER VALUE: 1
Run 2:
READ SALEID: S002
COUNTER VALUE: 2
Run 3:
READ SALEID: S003
COUNTER VALUE: 3
โก ODP and counter
are persisting across calls. You're not starting fresh.
โ
Scenario B: With *INLR = *ON
*inlr = *on;
return;
Every Run:
READ SALEID: S001
COUNTER VALUE: 1
โก Program resets file pointer and static variables on every call.
ODP is destroyed, static memory is released.
๐ง Summary
Behavior | Without *INLR |
With *INLR |
---|---|---|
File pointer persists | โ Yes | โ No |
Static variables persist | โ Yes | โ No |
Memory reused across calls | โ Yes | โ No |
Risk of bugs | โ High | โ Low |