RPG Developer Network News
RPG Developer Network
This is not your father's Q38
(c) 2001 by Robert Cozzi Jr.All rights reserved.

Thursday, April 26, 2001

Editor: Robert Cozzi, Jr.

OS/400 Version 5 Enhancements to RPG IV

A lot of nothing and a little bit of something


Overview

As you probably know, I have made a career out of RPG and RPG IV for over 20 years now. Since the mid 1980's, I have written 5 books and countless articles on the RPG language, I've taught the RPG language to thousands and thousands of programmers , and worked with IBM on the design of the last few enhancement made to the RPG III language. I've also had a heavy hand in influencing the design of the RPG IV language and many of its features.

Since the late 1980s I have have reviewed virtually every new enhancement to the RPG language, including several that haven't yet made the cut.  I've spent countless hours, even several months reviewing, rewriting, recommending, arguing and downright fighting for the features I have felt strongly about for RPG IV language and the RPG IV programmer. In fact, when I first when up to the IBM Toronto Software Development Lab, in the 1980s, all I saw were RS/6000 displays, not a 5250 screen in site. No wonder they didn't understand what RPG programmers wanted!

I am satisfied  in what my efforts have produced with respect to RPG IV, because I know that there are thousands and thousands of people out there earning a living by writing programs in RPG III and RPG IV. I have never been paid by IBM for this effort, nor did I expect to be.

I can say, however, with all confidence that I probably know the RPG language as well as anyone. Or sure, I've let my in depth knowledge of look-ahead fields and matching record processing lapse, but I do have a great book I can refer to should I ever come across a program with that kind of thing. ;) 

One of my early indications that I was destine to write a book on RPG was back in the early to mid 1980s. I was reviewing the RPG Cycle diagram in the System/38 RPG Programmers Guide and noticed it wasn't right. The diagram was incorrect as it did not properly document the timing of the Fetch-overflow routine of the RPG cycle. I filled out reader reply card in the back of the manual and sent it in. I'm pretty sure IBM eventually changed the documentation.

Today, in RPG IV I look at a language that has been greatly influenced by my efforts, the efforts of an RPG programming, not a compiler writer. Things like the PREFIX keyword, reducing the number of conditioning indicators from 3 to 1, consolidating the half-adjust (operation extender) with the opcode, using the + (plus sign) for concatenation in expressions, nested /COPY statements, the new ELSEIF opcode, and the EXTNAME keyword all have my finger prints on them. But there are still a lot of things that didn't go the way I would have liked them to. 

The biggest nuisance in RPG IV, today, I believe is that of the character selected as the parameter separator.  The colon causes a huge burden for me on what seems to be an almost day-to-day basis. So much so, that even after more than 5 years of using RPG IV, I still occasionally omit the colon from between parameters. Then I get that silly "expected token not found" message that only a compiler-writer could love. Even the debugger doesn't like the colons. Often the debugger can't detect the field name when it is adjacent to a colon. This first occurred in V3 R2, and continues to occur to this day on my V4 R5 machine.

The second largest problem for writing RPG code is the "tic marks". I've been a long-time advocate of eliminating the legacy "tic marks" from the RPG specifications. The two quintessential examples of a "tic mark" are the "E" and "F" for Externally Described files and "Full Procedural" or (Program-described as we call them) files. If there is a record length specified, the file is program-described, so why do I have to put the "F" in column whatever it is? If there isn't a record length, the file is externally described. This release of RPG is no different. 

 


What's New?

OS/400 Version 5 RPG IV has its most significant enhancements in the area of built-in functions. There are over 22 built-in functions added with this release. There are also variations of several of them. IBM has also added a couple of new opcodes; something they said they would no longer do. However, the context of the new function that these opcodes brings was justified. In fact, with the new design of the RPG language, I think you'll be seeing a reversal of the view that all new function will be implemented as a built-in function.

New Built-in Functions 

The new built-in functions offer no new functionality, but rather provide the means to use existing functionality in an expression. For example, there is now a %SUBDT built-in function that mimics the functionality of the EXTRCT (extract) operation code. %SUBDT is supposed to be "Substring Date" but to me, reads like "Subtract date". I guess the RPG compiler writers have never used the CL language; %SST is how we spell "substring" on this box. :)

Date-Related Built-in Functions

There are now built-in functions to do full date arithmetic in expressions. Previously, the ADDDUR and SUBDUR operation codes performed this function along with the EXTRCT opcode. There are new built-ins that provide the ability to convert a digit into a duration value, which can then be used in date arithmetic. The duration built-in functions are: %MSECONDS, %SECONDS, %MINUTES, %HOURS, %DAYS, %MONTHS, and %YEARS

The SUBDUR opcode's function equivalent is the %DIFF built-in function. You specify two date values, and a duration code, and it returns the duration between the two dates. Retrieving a portion of a date, time or timestamp field can be performed with either the EXTRCT operation code, or the %SUBDT (substring date) built-in function.

In addition the TIME opcode now has three built-in functions that perform equivalent tasks. %DATE retrieves the current date. %TIME retrieves the current time, %TIMESTAMP retrieves the current timestamp. In addition, each of these three built-in functions supports converting a non-date or time value into a date or time value. Simply specify the non-date or time value as the parameter of the built-in function. The value returned is a valid date or time value. This function is similar to using the MOVE operation with a date or time format code specified in Factor 1.

Table and Array Look Up Built-in Functions

The old LOOKUP operation now has two built-in function equivalents, with several variations of each. In order to support the control that the LOOKUP operation code's resulting indicators provide, IBM created ten variations of the built-in functions.

To support look up operations with arrays, the following built-in functions are provided: %LOOKUP, %LOOKUPGT, %LOOKUPGE, %LOOKUPLT, and %LOOKUPLE. For look up operations to table, with or without alternate tables, the the following built-in functions are provided:  %TLOOKUP, %TLOOKUPGT, %TLOOKUPGE, %TLOOKUPLT, and %TLOOKUPLE.

"String" Built-in Functions

Rounding out the so-called string-handling built-in functions are the %CHECK, %CHECKR and %XLATE built-in functions. Again no new function, just another way to perform previously available function, but this time, within an expression.

Miscellaneous Built-in Functions

To provide support within expressions for a few other operation codes, the %OCCUR, %SHTDN, and %SQRT built-in functions are provided. Not to sound like a broken record, but, again,  no new function, just expression-based versions of existing function.

File Specification Keywords

Say good bye to calling QCMDEXC within an RPG program just to do an override database command. We now have the long overdue EXTFILE and EXTMBR File Continuation keywords.

These keywords allow you to, at runtime, change the file and/or member name being processed by simply closing the file, moving the file or member name into a field, and re-opening the file. No OVRDBF needed. This is probably the most beneficial new function in RPG IV with V5.

While the keyword names are nothing to be desired, the keywords work the way you thing they should (at least I hope they do). You can specify a quoted file name or a field. If you specify a field, you simply move the name of the file into the field, and then open the file. The traditional file name in columns 7 to 16 of the File specification becomes a file handle. That is, you still read and write to that file name, but the actual file being processed is specified on the EXTFILE keyword. 

The file name specified for the EXTFILE keyword can be a fully qualified file name (using OS/400 syntax library/file) or it can be the file name by itself. The value must be left-justified in the field name specified for the EXTFILE keyword. Granted this syntax is different from the other two areas where a file and library are specified in RPG, but no one ever accused IBM of being consistent. 

The member name specified on the EXTMBR keyword can be a literal value, or a field name. Any member name can be specified or one of the two special values for member names, can be used. *FIRST indicates that the first member in the file is to be used. *ALL indicates that when the file is open, a special override is applied and all members in the file are open as one lengthy member.

One other change to File Specification keywords is support for named indicators on the OFLIND and COMMIT keywords. 

Compiler Directives

One of the first things I asked for when the /DEFINE, /IF and so forth, compiler directives were introduced was to be able to check the version of the OS/400 on which I was compiling. That way, if IBM ever provided an easier way to do a complex task, I could condition the source code based on the operating system version (running the old code if I wasn't on the new release). Unfortunately, the way they write compilers, the only way that kind of feature would be useful is if they introduced it on the same release as the compiler directives. For example, I should have been able to check the release on which I was compiling since OS/400 Version 3, Release 7. Well, as of Version 5, Release 1 I can check the version by checking for the existence of a directive variable *V5R1M0.

Since IBM realized that this kind of function isn't useful unless it is available on earlier releases, they are back-porting this enhancement to Version 4, Release 4 via PTF. It would have been better if they went all the way back to V4 R2 since going "back" to V4R4 is really the same as V4 R5 since there were no changes to RPG IV in V4R5. 

How does it work? In your RPGIV code, you use the /IF DEFINED(*V5R1M0) directive. If you're compiling on V5R1 or later, the condition is true, and the code following the compiler directive is included in the compile. If not, the source code is omitted from the compile. In addition, you can check which compiler command was used to compile the source member by checking for *CRTBNDRPG or *CRTRPGMOD using the same technique as used by the version checking code.

Also, the /COPY directive now has a /INCLUDE equivalent (I guess we need at least two ways to do everything, no matter what it is). Actually, I believe this was done for two reasons. (1) Most other languages use the term INCLUDE instead of COPY when including source from another member, (2) There's a move within IBM to redesign the SQL preprocessor and "do it right". I suspect /INCLUDE is staged to support that rewrite, should it ever occur. 

 


New OpCodes

Interestingly, even though IBM has suggested that there will be only new built-in functions and few, if any new operation codes, they've actually provided four new operation codes with OS/400 Version 5. MONITOR, ON-ERROR, ENDMON, and ELSEIF.

MONITOR - Monitor for an error

The MONITOR operation sets up an event handler for a monitored group of statements. This event handler works similar to a MONMSG command in CL. It establishes a block of code (group of RPG statements) that are run when an error occurs within the monitored group. 

To set up a monitored group, you type the MONITOR operation code, then follow it with the statements for which the monitoring applies. Then, after the final statement in the monitor group, type the ON-ERROR operation with the RPG Status Code error ID in Factor 2. These are the same status codes found in the *STATUS position of the INFDS and PSDS data structures, and in the contemporary %STATUS built-in function. 

ON-ERROR - Set Up Event Monitor

You can specify one or more status codes with the ON-ERROR operation. This is similar to using a MONMSG command in CL with multiple message IDs specified. As always in RPG IV, you separate multiple status code with a colon. :(

There are three identifiers that you can use to create a more generic handler. In place of a specific status code, specify *PROGRAM to indicate that any program status code (i.e., those in the range of 1000 to 9999) are monitored, or *FILE to indicate that any file-related status code (i.e., those in the range of 100 to 999) are monitored. Optionally, you can specify *ALL for the status code that, obviously, monitors for any status code to occur.

The documentation is NOT clear as to whether you specifically need to code the Error Operation Extender in order to enable the monitor group. However, there are no examples that utilize the E extender, nor is there any mention of it, so I believe it does not apply in this context. Thank goodness!

In the example the follows, a monitor group is established. Line 10 is the MONITOR operation which begins a block of code that will be monitored. Lines 20 through 50 are the lines that are monitored. Line 60 monitors for file status code 1021, while line 80 monitors for any file status error code. Since line 60 explicitly monitors for 1021 and appears before the ON-ERROR on line 80, when 1021 is issued, line 60 receives control and performs the call to the DUPKEYDETECTED routine. Any other file-related status code causes control to be passed to line 80.

If no exception/error events occur, the monitored group of statements runs normally, and the next line of code to run is the one following the ENDMON operation code.


.....CSRn01Factor1+++++++OpCode(ex)Factor2+++++++Result++++++++Len++DcHiLoEq
0010 C                   MONITOR   
0020 C                   EXFMT     EditCust
0030 C                   if        CustNo > 0
0040 C                   Write     CustMast
0050 C                   endif
0060 C                   ON-ERROR  01021
0070 C                   CallP     DupKeyDetected
0080 C                   ON-ERROR  *FILE
0090 C                   CallP     DupKeyDetected
0100 C                   ENDMON

So, are you ready to forget to type in the '-' for the ON-ERROR opcode?  Who thought that one up?  :(

 

ELSEIF (Else clause consolidated with an integrated IF statement)

About Version 3 Release 2 or Release 7 it became clear that something was missing from RPG. I sent a note off to IBM Toronto and suggest that we all overlooked something so obvious that it was funny. And that was the ELSEIF operation code. Why, in 1999 (or whatever year it was at the time) do we still have to write one line for an ELSE followed by another line for the IF condition?

IBM agreed and in Version 5 they introduced ELSEIF operation code. This operation code consolidates the ELSE and the IF opcodes by integrating their function into one ELSEIF operation. 

Factor 2 of the ELSEIF operation supports everything the traditional IF operation supports. So now, instead of coding an ELSE opcode on one line, and an IF opcode on a second line, you can code one ELSEIF operation to handle the situation.

But the ELSEIF goes one step further. It eliminates the requirement to code a closing ENDIF opcode. Unlike the IF opcode which requires a corresponding ENDIF opcode to close the IF condition, an ELSEIF uses the same ending ENDIF operation that the opening IF operation uses. That is, only one closing ENDIF statement is needed! Pretty cool. In fact, this effectively does the same kind of function as the SELECT/WHEN/OTHER/ENDSL operation, so perhaps more RPG developer will use this operation since SELECT/WHEN was often seen as too complex by some developers.

 


New /FREE Compiler Directive

I was almost going to avoid writing about this, since it goes against the spirit of RPG IV, but... The new /FREE and it closing directive /END-FREE allow you to isolate a set of source statements, much like the /EXEC SQL and /END-EXEC directives do. 

/FREE and /END-FREE, however identify a non-columnar operation code area. That is yet a 3rd Calculation specification. This time, however, the Extended Factor 2 begins where the Level break indicator normally begins (i.e., column 7) and extends to the end of the line. There are other differences too, including:

The /FREE directive introduces several new elements into RPG IV:

For the most part, and to IBM's credit, the syntax is no where near as poorly designed as the first half dozen or so attempts at it. The syntax, at first glance appears to be reasonable consistent within itself except for requiring conditional statements (IF, ELSE, FOR, etc.) to be terminated with a semi colon also. Is it me, or is this ugly?

      /FREE
          If  Price > 0;
          Eval   Price = Cost + MarkUp;
          elseif Price < 0;
          Eval   Price = 0 + MarkUp;
          elseif Price = 0;
          Eval   Price = MarkUp;
          endif;
      /END-FREE

I wonder how many times I'm going to leave off the ending semi colon on the IF and ENDIF statements? I can tell you now, every time I write that code. Hence I will not be using /FREE directives for the foreseeable future.

I believe most people will avoid using this new syntax for two important reasons:

  1. It is not backwards compatible with prior releases of OS/400. Consequently software houses will not use, probably, until OS/400 Version 6 is released in 3 or 4 years.
  2. An additional skill set is required to maintain /FREE code. If I am an IT Manager, do I want RPG IV with fixed format, RPG IV with EVALs and expressions, or do I want RPG IV with /FREE source code embedded in my systems? 

I find management resistance to RPG IV Procedures to be medium to high. I doubt they will support utilizing /FREE for maintaining applications or new code, particularly since there is no new function in /FREE, just alternative syntax. Let's look as how many different techniques there are for doing an ADD operation in RPG IV:

1) Traditional long-form ADD operation code:

     C     Cost          Add       MarkUp        Price

2) Traditional short-form ADD operation code:

     C                   Z-ADD     Cost          Price
     C                   Add       MarkUp        Price
 

3) Contemporary EVAL operation code:

    C                   Eval      Price = Cost + MarkUp    

4) Contemporary EVAL operation code enclosed in /FREE /END-FREE directives:

      /FREE
          Eval   Price = Cost + MarkUp;
      /END-FREE

5) EVAL operation code enclosed in /FREE /END-FREE directives without specifying the OpCode name:

      /FREE
          Price = Cost + MarkUp;
      /END-FREE

 

Conclusions:

All in all, the OS/400 Version 5, Release 1 edition of RPG IV is on par with that of OS/400 Version 3 Release 7 in volume of features, and Version 4, Release 4 in functionality. The new MONITOR/ON-ERROR operation codes are probably going to be very well utilized once RPG programmers become familiar with why you may want to use them, and the ELSEIF operation code while effectively the same as a SELECT/WHEN statement will no doubt be used almost immediately since many programmers still don't utilize SELECT/WHEN. ELSEIF on the other hand, will probably be comprehend the used almost immediately.

But again, unfortunately, the way IBM writes compilers, new functionality is not backward compatible with prior versions of OS/400. This is unfortunate because it effectively prohibits the use of any new function in RPG for at least 18 months. Typically the only people that utilize the new function are magazine writers. Expect a series of up coming articles on the new function in Version 5, RPG IV, particularly the /FREE stuff. This tends to occur simply because the magazine writers are so board writing about yet another way to use the DOW opcode that they instantly jump on the latest and greatest.

But as you're reading those articles and you start to get the feeling that your shop is the only one not using the new /FREE directive, fear not, the odds are with you. As of January 2002, less than 10 percent of all AS/400 and iSeries shops were running V5 R1.

For now, when it comes to RPG IV, the new ELSEIF opcode, the EXTFILE and EXTMBR keywords and the MONITOR/ON-ERROR operation codes are the stars of OS/400 Version 5, Release 1. 

RPG Wish List: Make all new releases of the RPG IV compiler run on V5R1.

<< Back to RPG IV dot com