Programming / RPG
RPG programmers know how powerful the language is, and IBM just keeps making it better.
Welcome to RPG for Version 7.1 of IBM i. Version 7.1 is a marked departure from previous releases. For example, this is the first time we've gone from one complete version release to another—from 6.1 to 7.1. A lot of buzz is in the air about some of the big-ticket items, like the new Open Access capabilities of RPG. But for those of us in the trenches, IBM has done a great job of taking the world's best language for developing business logic and making it even better. Let me show you a few examples of just what they've done for us.
Version 7.1 contains nine enhancements to RPG:
- Sort and search on data structure arrays
- Support for ALIAS names
- New and updated built-in functions (BIFs)
- Optional prototypes
- Performance improvement for large return values
- New XML-INTO options
- Automatic string conversion
- Debug data encryption
- Teraspace storage model support
What I find really interesting about this list is the breadth of it: these enhancements range from syntactical changes that make programming easier to program creation changes that really help packaged software developers.
I really want to focus on these things not so much as a programmer but as a systems architect and even more as a CIO trying to determine the future of my application environment. In my opinion, a number of these changes can be used to further support the argument for RPG's position as the primary business logic repository in a heterogeneous application environment.
Working and Playing Well with Others
The two big enhancements centering on interaction with the outside world are the broad support for long names and the new options for the XML-INTO operation.
ALIAS support is one more incremental step away from the old RPG II legacy and toward the sort of file I/O that programmers of other languages understand. It extends the QUALIFIED keyword, which suppresses the automatic generation of input and output specifications (thus removing a whole set of variables that are implicitly global in scope). The lack of global variables requires that all I/O is done to data structures. The only fly in the ointment at this point is the limitation of 10-character field names in externally described files. The ALIAS keyword does away with that limitation, allowing the full long field names of SQL tables to be used and thus removing one more of those conspicuous characteristics of RPG that make recent generations of programmers scratch their heads and go, "Huh?" Of course, long qualified names require more typing, but that's why you're using a wonderful tool like Rational Developer for Power (RDP), right?
So ALIAS helps RPG better coexist with relational data. The changes to XML-INTO make it easier for RPG to handle XML data. One thing that XML-INTO doesn't handle extremely well is leaf nodes that have both attributes and data.
<comment user="joepluta" time="12:35:06">Very Cool!</comment>
In this case, the comment element has attributes (user and time) as well as actual text data between the comment and /comment tags (the "Very Cool!" part). Using the existing XML-INTO capability, you can read this data into a data structure–called comment with subfields for user and time. However, there's no place for the comment text itself. The new datasubf option on the XML-INTO operation allows you to add a field to the comment data structure (say, "text") and then specify it as the target for the text data: datasubf=text. The text data would then be read into that field. As the text says, very cool!
The countprefix option allows you to specify a field that will be filled in with the number of values actually read when parsing data into an array of data structures. I won't go into detail about the new syntax for sorting and searching arrays of data structures, but I can see some very nifty tricks that involve the countprefix option and the use of %SUBARR and the new sort and search capabilities. The RPG Cafe has a really good writeup on the new capabilities here, and you can actually get them via PTF SI34938 for version 6.1.
One of my favorite enhancements is one that will probably slip under the radar for most developers: the ability to encrypt debug data. As a software vendor, I write software that is licensed to others. The majority of commercial software for the IBM midrange has been semi-custom, which means it was typically installed at a site and then further customized by the end user. This meant that the end user got the source code for everything…almost. Just about every package had one or more programs that had no source; these were the security programs, and they couldn't be touched. They did all the magic that made the system work properly and also checked the license keys. If the user got source to that program, your licensing scheme was toast.
For someone like me, who sells utility applications and tools, the same idea applies, but we tend to not provide source for any of the product. Again, this helps us keep the product secure and licensed. However, there's a big downside to this particular approach: you can't debug the programs.
The debugger likes to have source available; this allows it to provide a more meaningful debugging environment by showing the source code the program is executing and formatting the contents of data into a human-readable display. This is usually enabled by including either the source or list view in the program object itself. However, including this information in the program also makes it available to be extracted, which in turn allows an unscrupulous party to defeat any security scheme you might have in place.
Enter the new DBGENCKEY keyword! This keyword allows you to specify at compile time a key that will be used to encrypt the debug data. A corresponding keyword on the STRDBG command then allows you to specify that key to decrypt the data for the debugging session. Just one more way to make the platform better-suited for commercial application development!
The other architectural enhancement has to do with the teraspace storage model. If you're not familiar with teraspace, you don't need it. Yet. But you will likely run into it eventually. Teraspace is the capability of handling truly enormous quantities of data within a single process without having to write it to a database. Parsing XML files with gigabytes of data is just one situation where this capability is needed. Not only that, but the teraspace model actually can provide some performance enhancements because, somewhat paradoxically, the pointers for teraspace are actually smaller than those of the traditional single-level storage (SLS) model (64 bits for teraspace as opposed to 128 bits for an SLS pointer). I won't go into the specifics; for an introduction to the entire teraspace concept, you can go to the online version of the ILE concepts manual for V5R2, Chapter 4. Or you can download the PDF of the later versions, such as V6R1. (You can in fact find lots of good reference material at the RPG Café.)
The enhancement has to do with specifying which model to use. The new feature allows you to inherit the storage model from the calling program, which effectively means that you no longer have to specify the storage model. This isn't a silver bullet; unless your entire application is set up for this capability you can still run into problems, because programs in a single activation group must have the same storage model. An odd little side effect of this is that ILE programs no longer default to activation group QILE. Instead, the new default is *STGMDL, which selects either QILE for SLS programs or QILETS for teraspace-enabled programs.
This enhancement may also slip under the radar, but it's really quite important. One of the drawbacks to RPG is that it is a very strictly typed language. That is, its variables have not only a type but also a specific length. Even VARYING character fields have a maximum length. Because of this, creating generic procedures has been somewhat of a problem. The way many people have gotten around this is by specifying large values. The problem with arbitrarily large parameters is that they cause a lot of data to be copied back and forth. You can minimize this problem to some degree with parameters by passing the parameters by reference; you then pass only a pointer. However, there is no corresponding technique for handling return values, at least until now. The new RTNPARM keyword instructs the compiler to create a procedure as if the return value were actually a hidden parameter. This way, you can pass just the pointer back and forth, and the performance can be greatly enhanced for procedures that return widely varying amounts of data. This is one of those things that seems deceptively minor but can really allow you to modularize your code. One part of the code can deal with formatting a large buffer of data, while the other can deal with transmitting it to another point in the network. This separation of duty allows either component to change independently.
This enhancement has the potential of really changing the perception of the language for newcomers. RPG supports procedures, but until now, you have always had to execute double programming by creating both a prototype and a procedure interface. Not only is the prototype redundant, but it can also be confusing because it seems to define variables, even though the names used on the parameter definitions in the prototype aren't usable within the program. The real use of a prototype is to define the signature (the characteristics of the parameters and return value) of the procedure to an external caller. And to that end, IBM has relaxed the requirements, making it no longer necessary to specify a prototype for a procedure. This puts it closer to many other languages.
This is absolutely a double-edged sword. Hopefully, it will encourage development shops to create a standard in which all externally called procedures are prototyped in copy books, which are then included in both the calling modules and the defining module. Including the copy book in the defining module will force the definitions to match, so any other module that includes the copy book will work. However, it does allow programmers to be lazy and define the prototype only in the calling program. This behavior is especially likely among us older programmers, since it's almost identical to the concept of manually defining PLISTs in each program that called another program. It has the same drawback: if you change the called program and don't change all the calling programs, you will almost certainly create runtime errors.
However, since you don't have to create prototypes for internal procedures, I think it becomes an almost inviolable standard for every externally referenced procedure (including the main procedure for bound programs) to be defined in a copy book.
Only the Beginning
This is just a glimpse into the upcoming release. Hopefully, I can cover more of the enhancements in detail in upcoming articles. Until then, though, I hope you are excited about the changes; they show that IBM still considers RPG a powerful component of its ongoing application development strategy.