Back in my early days of the IBM midrange platforms, RPG was known as primarily being a Report Program Generator (although the "Generator" part was a little over-optimistic!). This was back when writing interactive programs with RPG was a black art of shoehorning the RPG cycle into something in which it clearly did not fit.

But with enough effort, some slamming your head into the wall, and a little time with a Shelly Cashman textbook or two, it was possible back in the day to write serviceable interactive RPG programs. That code was never going to win a Most Beautiful Code Contest, but it did the job. After spreading my wings and learning other languages, I realized the value of indented, expressive, and obvious code — code written as much for eyeballs as for a compiler. Alas, even with the advent of the mid-90s era of ILE RPG, RPG persisted as a compile-only language very unfriendly to both eyeballs and quick comprehension. I’ll go out on a huge limb here and flatly state that our old RPG, regardless of how good a coder you are, was simply impervious to being expressive and obvious.

I am late to the party, but the other day I started noodling around with the 7.1 Technical Refresh of ILE RPG, the one that provides full "free-form" RPG capabilities. In very short order, I was outrageously impressed. Nits remain to be picked with several syntactical aspects of the language, but for the first time ever, I am writing RPG that is expressive and comprehensible. If you write RPG for anything serious, you owe it to yourself to dig into the 7.1 Technical Refresh RPG. It will forever change how you write RPG. While the refresh doesn’t add any great new functional changes, RPG programming power previously straight-jacketed by column reliance quickly comes shining through.

This article features an example RPG program I wrote with the TR 7.1 RPG free-format syntax. I’m a rusty RPG coder to be sure, so if you see anything glaringly stupid (for which I have a knack!), please let me know. I cut a few corners to keep the code short, and at 191 lines I’m probably pressing my luck. But it’s 2015, and articles like this are no longer constrained by the printed page, so bear with me. I won’t cover every line of the RPG in detail in this article, but all of the project’s source, including the RPG, is available here for easy download for further inspection (you don’t need a Git client to download the code—look for the "Download Zip" button).

Making it mobile

I thought ILE RPG’s spanking new syntax was worthy of a spanking new user interface, so the program I wrote is an ASNA Mobile RPG (MR) app. MR apps are HTML5 apps primarily intended for smartphones and tablets, but they also run on desktop browsers. They feature performant and secure IBM i database connectivity. The app presented here is a simple little customer CRUD app with, for a little more sizzle, a map of the customer’s address.

The intent of this article is two fold:

  1. To show TR 7.1 ILE RPG in action. A full RPG program shows more context and capabilities than just a few snippets of RPG here and there.
  2. To show an RPG model that provides a (use your imagination here) work-with panel-like UI for a mobile app. Mobile idioms are vastly different than what we used to use in the green-screen, but as you’ll see, MR abstracts away mobile uniqueness and empowers RPG coders to create IBM i mobile apps with nothing but RPG.

The ASNA Mobile RPG mobile display file

Before digging into the ILE RPG for this mobile app, let’s take a quick tour of MR’s mobile display file. This isn’t really an article about ASNA Mobile RPG (MR) as much as it is about ILE RPG (I wrote an article a while back that goes into more Mobile RPG detail that can be read here). While there are a few things to understand about Mobile RPG, thanks to IBM’s Open Access API, there is less than you think. Mobile RPG provides a Windows-based mobile UI designer. It lets you create mobile display files with record formats, just like old-school display files. MR enforces the traditional indicator-driven "contract" between an RPG program and its display file.

The three steps to creating and running an ASNA Mobile RPG app are shown in the figure below. 

Figure 1: Creating and running an MR mobile app requires three steps. 

Figure 1 above summarizes the three steps for creating and running an MR mobile app.

A little detail for each step follows:

  1. Create the mobile UI. MR provides a Windows-based designer for creating the mobile UI. It includes all of the user interface elements you’d expect for a mobile user interface (including text boxes, buttons, navigational bars, map, data charts, data list, signature capture, images, and many others). Once you’ve created the mobile display file, you export it through MR as a traditional display file object on the IBM i. This display file will never be seen by eyeballs; rather, it exists purely to compile an associated RPG program. During this export step you can optionally save the exported display file source, which is mostly useful for learning purposes to see how all of MR’s user interface elements map to RPG idioms.
  2. Write an RPG program. This program provides the logic and file IO for your mobile app. It is compiled against the display file object created by the export process in Step 1.
  3. Run the mobile app. The MR mobile app is an HTML5 browser-based mobile app that runs in mobile (and desktop) browsers. At runtime, IBM’s Open Access API intercepts this RPG program’s display file data and routes it to and from the MR mobile user interface. That the traditional display file is swapped out for the mobile display file at runtime is completely transparent to the RPG program.

Let’s take a closer look at the example app’s three display panels (which are actually surfaced as display file record formats).

The Mobile List Panel

The initial screen for this example app is the list panel shown in Figure 2A.

Figure 2A: The mobile list display looks like this.

The initial screen for the list panel’s format name is CUSTLIST. It is scrollable, and a user can select a row one of two ways: the user can either tap on the customer’s name or tap on the chevron on the right end of the row. This list effectively presents the work-with panel model for mobile devices.

Because this is an example of an IBM i app, it assumes it might be using an input file with a great deal of records, thus the "Next" button to get the next page of rows. For this example, six rows are shown and the display isn’t scrollable. However, the number of rows displayed is controlled by a constant in the underlying RPG program. Unlike a tethered green-screen, apps like this need to be written with performance in mind. The user doesn’t want to wait for hundreds of rows to load (but it might also be reasonable to load more than I am loading here).

The Mobile RPG designer is used to map function keys to button (and other UI element) taps. In this panel, the F3 key is mapped to the "End" button and the F5 key is mapped to the "Next" button. The record format name for this list panel is CUSTINFO.

This customer list is populated in the ILE RPG as a very simple subfile. This subfile has the following configuration assignments:

Subfile nameCSTSBF
Subfile controller nameCSTCTRL
Clear subfile indicator99
Main text field nameCSTXT
Main text field length70
Secondary text field nameCSTDTL
Secondary text field length     50
Selection field nameCSTSEL
Value fieldCSTVAL
Value field length30

The CSTSEL field is a single-character field that is populated implicitly by MR with a ‘1’ when a user taps the row. RPG’s READC operation is then used to identify the row selected. The CSTVAL field is a "hidden" field used to stash hidden data for a row. In this case, the customer number is stored in this field (so that when a row is selected, via READC, the customer number is available).

The Update Panel

The mobile update panel is shown in Figure 2B.

Figure 2B: The mobile update panel shows a customer’s information.

The update panel, which is format CUSTINFO, is shown by tapping on a customer name from the list panel. The user can change any of the fields presented and tap OK or tap Cancel. Tapping either button returns the user to the list panel.

In this panel, the F2 key is mapped to the "Back" button and to the “Cancel” button, the F8 key is mapped to the "OK" button.

The Map Panel

The map panel, shown below, provides geo-location functionality.

Figure 2C: The map panel shows a customer’s location.

The map panel, which is format CUSTMAP, is displayed for a customer when the chevron is tapped on the list panel. With an ILE RPG program providing this mobile app’s logic, Mobile RPG needed an idiomatic RPG way of providing the addresses for a map. In this case, a single address is mapped, but the Mobile RPG map control can map many addresses.

The map control is fed addresses through a simple RPG subfile. This subfile has the following configuration assignments:

Subfile nameMAPSBF
Subfile controller name      MAPCTRL
Clear subfile indicator99
Address field nameLocation
Main text field length60

Clicking back returns the user to the list. After exporting the display file these three record formats comprise, the residual DDS display file source member is shown (Figure 3 below). Take a look at it and notice that its fields and subfiles resolve to those explained above.

Figure 3: This DDS display file source is generated when MR mobile UI is exported as a display file object.

Think of MR’s exported display file object as a proxy for the mobile UI. At compile time, the RPG program will reference this proxy display file, but at runtime, through Open Access, the MR mobile display file is used. Once again, the proxy IBM i display file is never seen by human eyeballs.

With the MR mobile display file and its IBM i proxy display file created, let’s turn our attention to some of the interesting parts of the ILE RPG source code. Because MR so well abstracts away the notion that we’re really creating a mobile app, the RPG is written (and can be examined) without regard for it really being a mobile app. Just think of it as powering three simple traditional display file formats (which, by the way, is exactly what it’s doing).

The ILE RPG source

The full RPG source is shown below in Figure 4A and the single /COPY member it includes is shown in Figure 4B. A brief code narrative follows these two listings.

Figure 4A. The full ILE RPG source listing.

Narrative for several chunks of Figure 4’s RPG follows

Line 1

Define compile time options for the program.

Lines 2 – 12

Declare the workstation file and two disk files (CustomerL2 is keyed by customer name and number, and CustomerL1 is keyed by customer number only). The workstation file continuation on line 4 registers this RPG program with the Open Access API. This is the RPG program’s only nod to it not using a traditional display file.

Lines 14 – 15

A very cool RPG feature, these lines provide fully qualified key definition data structures for the two disk files. These one-line shortcuts serve as KLIST alternatives (albeit vastly more programmer-friendly).

Lines 17 – 18

These are two global variables for the program (using local variables in procedures substantially reduces global variable dependence).

Line 20

Include the INFDS copy member (from Figure 4B below) and its constants. This enables the very old-school trick of interrogating the hex value of INFDS’s position 369 to determine what function (or special) key was pressed. Positions 260-270 also define and interrogate the last-written display file format as “CurrentFormat”. This field is instrumental in guiding this program’s logic. (As an aside, I was amazed to realize that, with Mobile RPG and IBM’s Open Access API, this INFDS data structure feature works just fine! The INFDS data flows naturally out of, and back into, the RPG program through Open Access.)

Lines 22 – 34

Declare a fully qualified data structure named “Action” that maps the function key constants (declared in Figure 4B’s copy member) to semantic actions. This lets the programmer think not about function key presses, but about user actions selected (such as a list’s chevron having been tapped). My longer-term plan for this data structure is to map reusable and generic “actions” to function keys and then move that definition to the Figure 4B copy member. Note that a couple of these actions are defined multiple times. This is for those times when a “Back” action is different from a “Cancel” action (for example) semantically but both are implemented with an F2 key press. I was surprised to find what appeared to be keyword-type conflicts with some field names in RPG data structures. For example, the ILE RPG does not at all tolerate an action being named “Next,” to my great disappointment. This is why there is a “More” action; I’d sure rather have a “Next” action.

Lines 36 – 38

Here’s the mainline code to bootstrap the program. These three lines populate the initial customer list. There aren’t any subroutines in this program; those have been dispatched and replaced with procedures. Thanks to TR 7.1’s free-format procedure declaration, you no longer need to bleed to death to remember how to declare a procedure and its interface.

Lines 40 – 104

This is the main loop of this program. This loop is wayyyy too long to be considered good code in anyone’s book. I sacrificed code quality here for slightly shorter source listing and less eyeball hopping required to comprehend the code.

Lines 42 – 49

This is the point in the narrative, were I explaining this to my father, where he’d throw up his hands and say, “Enough about the labor pains! Show me the baby!” This is where the fully qualified data structures, mapping function keys to semantic actions, and RPG automatically tracking the most recent record format really pay off. While it’s really a stretch, this RPG code almost presents itself as three controllers for three routes (the three record formats), each having at least one action. You can easily see that, for the CUSTLIST format, the program allows three actions: ItemTapped, ChevronTapped, and More. These three actions (and the Exit action) are the actions available on the CUSTLIST panel.

Lines 46 – 46

You didn’t get to write RPG like line 46 when Saturday Night Fever was number 1 at the box office! This line calls a procedure that accepts a single integer argument and returns a Boolean value which indicates if a record was read. I’ve left the error-handling as an exercise to the reader (That’s usually what writers say when they don’t know how to do something! In this case, I promise, it’s to minimize the code sample).

Lines 74 – 75

When the CUSTINFO panel is displayed (Figure 4B) and the OK button is tapped, the program needs to return to the customer list (Figure 4A), but reposition it to the customer just updated. RefreshCustList is a procedure that does just that. It is passed the customer name and number for which to position the list.

Lines 113 – 143

The LoadCstLst procedure loads up to the constant MAXROWS value of rows into the subfile displayed in Figure 4A. Note the variable RowCount is declared locally (so therefore it isn’t available to the rest of the program) and don’t forget that disk files can also be declared locally to procedures. Otherwise there isn’t much RPG here of any major interest, but it is interesting to note that this journeyman RPG is actually populating a list to be displayed on a smartphone.

Lines 156 – 163

The ReadCustById reads a customer record from the CustomerL1 file by customer number. Line 157 declares the procedure’s interface (where N is a much-needed shorthand for the procedure name). If an RPG data type is declared after the N, that is the type that the procedure returns. There must be a Return opcode with a variable of that type in the procedure to return the value to the caller. Any variable declarations between the Dcl-Pi and the End-Pi define required arguments that must be passed to the procedure. For simple procedures (those that effectively take the place of subroutines) the Dcl-Pi/End-Pi declarations can be omitted. There is more to explore in the RPG presented than what’s covered in the narrative, but it all follows the patterns and explanations provided in the code narrative.

Figure 4B. External source member to define the INFDS data structure and its constants.

Give free a chance!

This article intended to show TR 7.1 free-format ILE RPG in action and also that, with ASNA Mobile RPG, you can put that ILE RPG to work building a vastly non-traditional but very powerful new application type for your IBM i. Reading code is always much harder than writing code, but IBM’s latest RPG refresh substantially raises the bar for being able to write readable RPG. IBM deserves a big tip of the hat for finally coming ‘round and providing us with this powerful, expressive RPG syntax. The IBM i is much better for it and you’ll be a much better RPG programmer using it. Please, please, investigate this new syntax. It is very much worth breaking out of your old school RPG comfort zone!

Resources for learning TR7.1 ILE RPG

Four Reasons RPG Geezers Should Care About The New Free-Form RPG, Jon Paris in IT Jungle (or anything else that Jon Paris or Susan Ganter have written about RPG—get your Google on!)

Simon Hutchinson’s RPGPGM.COM blog