If you’ve ever stared at a wall of fixed-format RPG code and thought, “This looks like it was written by a medieval monk with a ruler and quill,” then welcome to my world. I’ve spent far too many hours squinting at columns, indicators, and op codes that look like they were designed to test patience rather than logic. Thankfully, RPG has evolved, and RPGLE free-format is the shiny new sword we get to wield.
The last few weeks I’ve been revisiting a lot of old code from the era when my hair was dark, my waistline was slim and peak cool was anything that Don Johnson wore in Miami Vice. As I’ve been stumbling through an RPG2 to RPG3 to RPG400 to RPG Free conversion journey, I’ve been making notes. Now it’s time to stitch these RPG nuggets together, with a sprinkle of irreverence, and document some fresh OLD vs NEW RPG examples.
Why Free-Format?
Fixed-format RPG is like driving a 1980s Volvo: reliable, boxy, and indestructible… but not exactly sleek. Free-format, on the other hand, is like upgrading to a Tesla with its clean lines, modern syntax, and fewer chances of falling asleep at the wheel.
The goal is simple: ditch the cryptic op codes and embrace readable, structured code. No more indicators sprinkled like confetti across your source. No more spaghetti jumps with GOTO. Just clean, modern RPG that even your Java friends won’t laugh at.
I’m not going to talk about code editors in this blog – we already know that VSCODE is a better code editor than the old integrated SEU (Stoneage Editing Utility) for IBM i programmers because it’s modern, extensible, and understands today’s RPG syntax, while SEU is frozen in time and doesn’t support newer language features. So, let’s look at some old RPG code examples against some new ones.
The Easy Wins
Arithmetic, assignments, and conditionals translate beautifully into free-format. For example, this old chestnut:
C Total ADD Value Total
becomes:
Total += Value;
Much easier to read, right?
Indicators can be vastly improved by giving them sensible names
C SETON 511289
or you could write the same in RPGLE like this:
*in51 = *on;
*in12 = *on;
*in89 = *on;
And if you’re still clinging to indicators like a toddler with a teddy bear, remember: named indicators are your friend.
Or better yet, avoid them altogether. Named indicators in RPGLE are a way to replace those cryptic numeric indicators (*IN01, *IN02, etc.) with something more readable and meaningful. Instead of remembering what *IN03 does, you can give it a name like EndOfFile or CustomerFound.
Here’s a simple example:
**FREE
// Declare named indicators
Dcl-S EndOfFile Ind Inz(*Off);
Dcl-S CustomerFound Ind Inz(*Off);
Exec Sql
Fetch Next From CustCursor
Into :CustRec;
If SqlCode = 100;
EndOfFile = *On; // Set named indicator instead of *INxx
Else;
CustomerFound = *On;
EndIf;
// Use the named indicators in logic
If EndOfFile;
Dsply ('Reached end of file');
ElseIf CustomerFound;
Dsply ('Customer record found!');
EndIf;
What’s happening here:
Dcl-S EndOfFile Inddeclares a named indicator variable.- Instead of using
*INxx, I flipEndOfFileorCustomerFoundon/off. - The logic reads like plain English: If EndOfFile… ElseIf CustomerFound…
Named indicators make your RPG code self-documenting. Instead of juggling numbers, you use meaningful names that tell you exactly what’s happening.
Tackling more Legacy opcodes and other tricky Stuff
The gnarlier op codes COMP, CASXX, CABXX, TAG, and the dreaded GOTO don’t exist in free-format. That’s a blessing in disguise because it forces me to rethink my logic.
Take COMP:
C VALUE1 COMP VALUE2 101112
If you are new to RPG, this code is saying: compare a variable called VALUE1 to a variable called VALUE2 and if its bigger seton a switch called INDICATOR10, if its less then seton INDICATOR11 and if its the same seton INDICATOR12. Later in the code we can refer to 10, 11 or 12 to look at what the comparison state was for those two variables. Smooth huh?
Instead of juggling indicators, I can write:
if value1 > value2;
// do something
elseif value1 < value2;
// do something else
else;
// equality case
endif;
Cleaner, safer, and no need to remember which indicator is secretly controlling program flow.
Goodbye Spaghetti: No More GOTO
If my codebase still has GOTO lurking around, it’s time for an intervention. Free-format RPG gives me structured alternatives:
ITERmeans jump to the top of a loopLEAVEmeans exit a loopLEAVESRmeans exit a subroutine
Now, I could also argue that each of these (ITER, LEAVE, LEAVSR) are just GOTO’s by a newer name. But I’m not going to this time. So there 🙂
Example:
FOR i = 1 TO 10;
IF i = 5;
LEAVE; // no more spaghetti jumps
ENDIF;
dsply('Looping: ' + %char(i));
ENDFOR;
Fresh RPG Example: Modernizing a Print Break
Here’s a new twist on the old CASGE example:
// Old fixed-format
C CurLine CASGE MaxLines PAG_BRK
Modernized:
IF CurLine >= MaxLines;
EXSR NEWPAGE;
ENDIF;
Or better yet, wrap it in a procedure:
IF CurLine >= MaxLines;
NewPage();
ENDIF;
Dcl-Proc NewPage;
dsply('--- NEW PAGE HEADING ---');
End-Proc;
Now my code looks like it belongs in the 21st century.
So now, we’ve slain the easy op codes, banished GOTO to the fiery pits, and modernized conditionals. But there’s still one more dragon to face: arrays and data structures. These are the places where fixed-format RPG really shows its age, like a dusty filing cabinet full of index cards. Modern RPG Free-format lets me swap that cabinet for a sleek database table or at least source-code that doesn’t make me cry.
Arrays: From Clunky to Clean
Fixed-format arrays often look like they were designed to test your ability to count columns. For example:
C 1 DO 10 i
C Arr(i) ADD 1 Arr(i)
C ENDDO
Free-format makes this so much nicer:
FOR i = 1 TO 10;
Arr(i) += 1;
ENDFOR;
No more squinting at column positions. Just a loop that looks like it belongs in any modern language.
Data Structures: The Glow-Up
Fixed-format data structures can feel like deciphering hieroglyphics. Here’s the old way:
I DS
I 1 10 Name
I 11 20 Address
I 21 30 Phone
Free-format lets me declare them like a civilized human:
Dcl-DS Customer;
Name Char(10);
Address Char(10);
Phone Char(10);
End-DS;
And accessing them is just as clean:
Customer.Name = 'Nick';
Customer.Phone = '1234567890';
Multi-Dimensional Arrays: Because One Dimension Isn’t Enough
Fixed-format multi-dimensional arrays were… let’s say “creative.”
Free-format simplifies multi-dimension arrays from one dimension (as above) to two dimension:
// Declare a 2D array of 3 rows and 4 columns
DCL-S matrix INT(10) DIM(3 4);
// Declare loop counters
DCL-S row INT(10);
DCL-S col INT(10);
// Populate the array with sample values
FOR row = 1 TO %ELEM(matrix:1); // Number of rows
FOR col = 1 TO %ELEM(matrix:2); // Number of columns
matrix(row:col) = row * 10 + col;
ENDFOR;
ENDFOR;
// Display the array contents
FOR row = 1 TO %ELEM(matrix:1);
DCL-S line VARCHAR(100) INZ('');
FOR col = 1 TO %ELEM(matrix:2);
line += %CHAR(matrix(row:col)) + ' ';
ENDFOR;
DSPly ('Row ' + %CHAR(row) + ': ' + line);
ENDFOR;
Key Points
DIM(3 4)→ First number is rows, second is columns.- Accessing elements →
matrix(row:col)uses a colon:between indices. %ELEM(matrix:1)→ Returns number of rows.%ELEM(matrix:2)→ Returns number of columns.
To the slightly more mind-bending multi-dimension array:
// Define a data structure template for each cell
dcl-ds CellTemplate qualified template;
id int(10);
name char(20);
end-ds;
/ Declare a 2D array of qualified DS elements
dcl-s grid likeds(CellTemplate) dim(3:4); // 3 rows, 4 columns
// Main procedure
dcl-proc main;
dcl-pi *n end-pi;
// Populate the array
for row = 1 to %elem(grid:1); // First dimension size
for col = 1 to %elem(grid:row); // Second dimension size
grid(row:col).id = (row - 1) * 10 + col;
grid(row:col).name = 'Cell ' + %char(row) + ',' + %char(col);
endfor;
endfor;
// Display the array contents
for row = 1 to %elem(grid:1);
for col = 1 to %elem(grid:row);
dsply ('Row ' + %char(row) +
' Col ' + %char(col) +
' => ID: ' + %char(grid(row:col).id) +
' Name: ' + %trim(grid(row:col).name));
endfor;
endfor;
end-proc;
Readable, logical, and no need to remember which column is secretly controlling your sanity.
The real magic of free-format is how easily I can wrap logic into procedures. Instead of scattering op codes across the program, I can write:
Dcl-Proc UpdateSales;
Dcl-PI *N;
Month Int(10);
Value Int(10);
End-PI;
Sales(Month) += Value;
End-Proc;
Now my code is modular, reusable, and doesn’t look like it was written in 1975.
Arrays and data structures are where free-format RPG really shines. Instead of fighting with columns and op codes, I get to write code that’s readable, maintainable, and dare I say it – enjoyable.
So, in just one blog, I’ve gone from medieval monk scribbles to sleek modern RPG. And the best part? I can finally show my code to a Java developer without them laughing.
Too much 😉
Final Thoughts
Converting fixed-format to free-format isn’t just modernization, it’s liberation! I’m freeing myself from cryptic syntax, indicators that haunt my dreams, and spaghetti jumps that make debugging a nightmare.
So, I grab my sword (keyboard), slay those op codes, and remind myself: friends don’t let friends use GOTO.
ONE FINAL THING Before you dive into the comments section to blast my code examples with better versions, remember these are just examples of how code might be written. Specifically written to be easily understood rather than efficient. Be gentle with me 😉
