Move to Free-Format RPG IV Part III

Article ID: 58202

Move to Free-Format

This is part III in a three-part series on moving to free-format RPG IV. In the first installment I covered the basics of free format. Then in the second part I talked about the details of MOVE/MOVEL alternatives in free format. This week I want to illustrate changes in coding habits in free format versus traditional syntax.

Whenever you learn a new language (programming or spoken), you have to adapt to some of the idiosyncrasies of that language, or you could have difficulty communicating with those who also speak the language. Free-format RPG IV is no different. It is a free-format language and should be coded the way most people code free format--not the way fixed format is coded.

For most people this simply means only a few changes to the way you program:

  • Avoid lining up the opcodes (i.e., Indent your code).
  • Use contemporary opcodes.
  • Use parentheses.
  • Use expressions.
  • Avoid numeric indicators 100 percent of the time.
  • Avoid ALL UPPER-CASE CODING.

Back when the C language was "the" language of the day, and IBM and others were advocating moving to it over RPG, one of the fingerprints left behind in C code written by RPG programmers was the lining up of the code near the left side of the line. This, of course, came from the decades-old habit/requirement in RPG II, RPG III, and subsequently in RPG IV to use the columnar syntax. When it comes to RPG IV free-format code, you can avoid this novice mistake by doing the following:

      /free
           setll *START custmast;
           read custmast;
(1)        dow NOT %EOF();
(2)           if (amtDue > 1.00);
(3)              msg = 'Your payment of ' + %char(amtdue) + ' is due on ' + %char(dueDate:*USA);
(4)              joblog('Customer %s owes %s by %s': %char(custno):%char(amtdue):%char(duedate));
(5)              if (%date() > dueDate);
(6)                 statMsg = 'Customer ' + %char(custno) ' account is past due ' +
(7)                              %diff(%date():dueDate:*DAYS) + ' days.';
(8)              endif;
(9)           endif;
(10)          read custMast;
(11)       enddo;
      /end-free

Let's review what we see here.

The first thing you should notice is that the code is not all left justified. This gives you a visual clue as to the nesting levels of the conditional statements and loops, similar to what you get with the INDENT keyword on the RPG III and RPG IV compilers for fixed format. By coding this way, you receive several benefits. The conditional and looping constructs (as I mentioned) are clearly visible. You can easily determine if you forget to insert an ending ENDIF or ENDDO statement and which one it is that you're missing. You can see the control structure, so adding additional or nested conditions is more easily accomplished. And you can isolate this block of code and, if necessary, move it to its own subprocedure.

Another, perhaps even more important, point of indenting is that other programmers can more easily read and comprehend your code.

Next, we've switched to using contemporary opcodes; pretty much had to in this example. Note the use of the implied EVAL opcode on lines 3 and 6, and the use of a subprocedure one on line 4. This subprocedure wraps a more complex API that, if it were used in-line here in our code, would only complicate things unnecessarily. It goes without saying that the DOW and IF statements are the contemporary versions of the DOWNE and IFGT opcodes (in this context), which leads us to our next point:

Using parentheses and expressions can clear up the code a lot. Lines 3 and 5 use parenthetical expressions to condition their code. If we need to modify the condition, it can be done quite easily by inserting the new conditions within the parentheses, or by adding an AND or OR clause to the existing conditional expression. Expressions also are used to build the message string on lines 3 and 4, as well as the one on lines 6 and 7. Using built-in functions is the way to go to streamline your code. But be aware that the original count of 9 built-in functions has long since grown to around 100 built-in functions. So check the manual or The Modern RPG IV Language book for the built-in function that's right for your situation.

Numeric conditioning indicators were all but eliminated back in RPG III through programming style. The idea was that no two-digit numeric indicators would be used to condition individual RPG statements. This left only Resulting Indicator use, as well as the move to using the so called named indicators, such as *IN32. So for decades we had code like this:

     C     *LOVAL        SETLL     CUSTMAST 
     C                   READ      CUSTMAST                               32
     C     *IN32         DOWNE     *ON
     C     AMTDUE        IFEQ      1.00
     C*** continue...

Indicator 32 is set on when End-Of-File is detected and therefore is used to control the DOWNE loop. The contemporary RPG IV free-format style does not support Resulting Indicators at all; therefore, the built-in functions are used to test for conditions, rather than the more obscure numeric indicators status.

      /free
           setll *START custmast;
           read custmast;
(1)        dow NOT %EOF();
(2)           if (amtDue > 1.00);
        // continue....

Note the use of *START instead of the *LOVAL figurative constant on the SETLL opcode, the use of %EOF() built-in function in place of *IN32, and the conditional IF statement in place of the IFEQ opcode. RPG IV free-format syntax is very strong compared with traditional fixed format and much more capable.

Finally, the use of all upper case; a point which always seems to find someone who wants to argue about it. But if you believe the world is flat, then go ahead and use all upper case. NO ONE WILL THINK YOU ARE SHOUTING AT THEM IN YOUR CODE.

The only legitimate "excuse" where all-uppercase code is being used is in eastern Asian countries where they teach English using capital letters to help simply the process of moving from Kanji to the Latin alphabet. But for the majority of code written today, mixed case or all lower case is preferred and should be your standard. If you're old enough to remember the old System/34 displays files, most display had text in all uppercase. This was simply because nobody told us programmers that a simple "Y" in column "something or another" would allow upper/lower case input vs. "caps only." But with System/38, and subsequently with System/36, the move to mixed case interactive displays was the standard. Unfortunately, RPG II and RPG III are all-upper-case-only languages. There's no reason they need to be, but they are. RPG IV is a case-agnostic language. It doesn't care if you type something in all lower case, mixed case, or all uppercase. They're all treated the same. Most other languages are case sensitive, which means that CUSTNO is a different field from CustNo or custno. But in RPG IV, they are the same field name.

So use mixed case or all lower case, whichever you feel most comfortable using.

Contemporary Features Exclusive to Free Format

After IBM introduced free-format to the RPG World, it continued to enhance RPG IV's features with new and important elements. The vast majority of these features work equally as well in traditional syntax as they do in free format. But recently, a few fringe features were introduced that, while certainly not mainstream, were important enough to be implemented even though they would not work with traditional syntax. Those features are:

  • Nested Data Structures
  • XML-INTO
  • XML-SAX

In my opinion, the single best enhancement to RPG IV since expressions is Qualified Data Structures. We all know that qualified data structures are data structures whose subfields are qualified to the data structure name using a period. This feature lets us reuse subfield names in any number of data structures. For example:

 
     D Order           DS                  Qualified Inz
     D  CustNo                        7P 0
     D  Number                        9P 0
     D  ordDate                        D
     D  totalDue                      7P 2
     D  lineItems                     7P 0

To access the subfields in the ORDER data structure, each subfield is qualified to the data structure itself, using a period, as follows:

      /free
             chain (order.custNo) custmast;
             setll (order.Number) ordHist;
             if %EQUAL(OrdHist)
                reade (order.number);
                if (%date() > order.ordDate + %days(5)); 
                    if (order.shipDate = D'0001-01-01');
                       joblog('Order %s from %s not shipped!':%char(order.number):%char(ordDate));
                    endif;
                    total += order.totalDue;
                endif;
             endif;

Any of the fields in the ORDER data structure may be reused as subfields of any other data structure or as stand-alone fields. Using qualified names in free format is much easier to accomplish than in traditional syntax. With the addition of the less widely used but still important Nested Data Structures, qualifications goes beyond the single subfield to data structure, as I've illustrated into the virtually unlimited nesting levels. Recently, in order to parse an XML document, I had to create a data structure with four nesting levels. Using those subfields in traditional syntax would have been challenging at best.

XML Parsing was added to RPG IV in 5.4 of the operating system and came in two versions: Easy and Difficult. The Easy version is in the form of the XML-INTO opcode. While I'm very disappointed in IBM using a dash within an opcode name, I do love the functionality the opcode brings to the language. XML-INTO lets you set up a qualified data structure whose subfields matched the names of XML elements/tags. XML-INTO then copies the data from the XML into the data structure's subfields--pairing them up by name. Simple and effective.

The Difficult version is the XML-SAX opcode, which is a part of the Simple API for XML. It requires callbacks and parameters and minor understanding of event-driven programming. It also requires you to move the data into the storage location of your choice--whereas with XML-INTO the target is the qualified data structure. If your XML parsing needs go beyond XML-INTO, you can always do it with XML-SAX.

Neither XML-INTO nor XML-SAX work in traditional syntax. Sort of like the MOVE/MOVEL opcodes don't compile if used in free format, XML-INTO/SAX don't compile if used in fixed format (including the Extended Factor 2 style of syntax).

Conclusions about Free Format

With 6.1 of the operating system about to be replaced with 6.2 and support for 5.3 reaching its end-of-support lifecycle, 100 percent of System i shops should have access to free-format syntax. Given that many IT directors who did not grow up in this System/3x space know very little about System i or RPG IV, it is important to know and use the more advanced version of the language. Why? Because adapting new requirements to existing, (well written) free-format code is infinitely easier than adapting it to any kind of existing traditional syntax RPG IV code. Whether it's inserting a new conditional statement, moving a block of code into its own subprocedure, or parsing XML, free-format RPG IV syntax is the only way any new code should be written. In addition, as an industry, we should be migrating our code to free format just like most of us did our RPG III code to RPG IV some 10 to 12 years ago.


Follow Bob Cozzi on Twitter at: Twitter.com/bobcozzi

Bob Cozzi is the author of Subprocedures and Service Programs. A 3-disc training series on DVD that gives RPG IV programmers an easy way to learn how to get started with RPG IV Subprocedures and of course Service Programs. It is available today at www.RPGWorld.com/DVD. Bob's website www.RPGWorld.com is also the place to download the source code featured here in RPG Coder and additional examples he's created over the decades. RPGWorld.com welcomes thousands of System i RPG IV developers each day from all over the world to share ideas and help each other with technical issues--and its free.

I use the same indenting guidelines as you except I start the first statement at the same column as the f in the /free directive. Seems a waste of space to indent here given the line length limitation. I think you gain more readability having fewer line continuations, then you get by indenting after /free. Regarding all uppercase, generally I don't use except for file field names. Lot of time I will cut and paste these, so rather than retype, I leave as is -- plus there may be some small benefit to distinguishing variables declared in the program from those that come from external files.

ProVIP Sponsors

ProVIP Sponsors