The Geezer’s Guide to Free-Form RPG, Part 3: Data Structures and More Data Definitions
May 28, 2014 Jon Paris
In my previous tip on the new free-form RPG support I discussed the basics of the new methods for defining data in RPG. In this tip I will be covering some additional aspects of the new style data definitions that are not so obvious from a simple reading of the documentation.
More on Data Definitions
Until now, if you wanted to ensure that all fields of a specific type (currency for example) used a common definition, you used the LIKE keyword. The one small problem with this was that you could not change the data type of the cloned field. If the base definition was packed, all of its clones were also going to be packed.
In the new free-form support, however, IBM has relaxed the rules concerning the use of named constants. Since one place where we can now use them is in the length definitions for fields, it provides us with an alternative approach. Take a look at the following example:
dcl-c DIGITS 7; dcl-c DECIMALS 2; dcl-s customerBalance Packed( DIGITS: DECIMALS); dcl-s invoiceTotal Zoned( DIGITS: DECIMALS);
Rather than clone a field definition, I can now specify the data type I want while still using a common set of length definitions. Now any time I need to change the size of these types of field I can do so simply by changing (say) DIGITS from 7 to 9.
Since I have already mentioned the LIKE keyword, I should probably point out one small change in that. If you currently have a definition like this:
D reportTotal S +2 Like(customerBalance)
It is not immediately obvious how to achieve the same thing in freeform, but the answer is quite simple. IBM has added a length adjustment parameter to the LIKE keyword. So to adjust the length of the cloned field we simply code that second parameter. Like so:
dcl-S reportTotal2 Like(customerBalance: +2);
This new flexibility in the use of literals does have one potential pitfall. It means that some keywords that previously accepted literal names without the use of quotation marks such as DTAARA, EXTNAME, and EXTFLD, now need quotes. In free form an unquoted name will always refer to a field or a named constant. So without the quotes the compiler will assume that the name references a constant and will flag a field not defined error.
So this fixed form code:
D myNewExtDs E DS ExtName(PRODUCTX) D myDataArea S 20a DtaAra(JONSDTAARA)
Cannot simply be converted to this equivalent:
Dcl-Ds myNewExtDs ExtName(PRODUCT) End-ds; Dcl-S myDataArea Char(20) DtaAra(JONSDTAARA);
But rather must have the quotation marks added like so:
Dcl-Ds myNewExtDs ExtName('PRODUCT') End-ds; Dcl-S myDataArea Char(20) DtaAra('JONSDTAARA');
Another potential pitfall that bit me during my early explorations of this new support concerns the use of ellipses in data definitions. Since I try to use descriptive field names in my code I often need to use these. Here’s an example:
D masterAccountDetail... D DS LikeDS(accountDetail_T)
In converting this manually it is tempting just to replace the initial D with Dcl-Ds, remove the D and DS from the second line and voila! You’re done. But the result as shown here won’t work.
Dcl-Ds masterAccountDetail... LikeDS(accountDetail_T);
The reason is quite simple: the ellipses tell RPG to continue the specification at the first non-blank character of the next line. So the compiler sees the LikeDS simply as a continuation of the DS name and a number of errors will result. Ellipses can still be used in free-form, but only to continue the name, not the specification as a whole. So the simple fix is to code it like so:
Dcl-Ds masterAccountDetail LikeDS(accountDetail_T);
Before I conclude this tip, just a quick word about the use of conditional directives in the new free-form. Previously we could only use such directives to selectively include or omit individual data declarations, or other code blocks. But we could not use them to selectively use part of a definition. With the new support we can. Here’s a simple example based on the idea that we might want to have a single source but be able to use it to generate both a UTF-16 (double byte) version of the program as well as a conventional single byte version. Using the new support it can be done like this:
Dcl-s accountName /If Defined(UTF16) ucs2(40) ccsid(1200) /Else char(40) /EndIf ;
If the condition UTF16 is defined at the time the program is compiled, the accountName field will be defined as usc2(40), but if it is not in force the field will be defined as char(40). It appears as if the concluding semi-colon has to be placed outside of the conditioned code as shown here. I would rather have been able to add it to both definitions in the knowledge that only one will be used. Hopefully we may see that change in the future.
That’s all for this tip. Next time we will be look at how the new support changes, and in many ways simplifies, the definition of prototypes and procedure interfaces. Until then if you have any questions or comments please let me know via Ted Holt by using the IT Jungle Contact page.
Jon Paris is one of the world’s most knowledgeable experts on programming on the System i platform. Paris cut his teeth on the System/38 way back when, and in 1987 he joined IBM’s Toronto software lab to work on the COBOL compilers for the System/38 and System/36. He also worked on the creation of the COBOL/400 compilers for the original AS/400s back in 1988, and was one of the key developers behind RPG IV and the CODE/400 development tool. In 1998, he left IBM to start his own education and training firm, a job he does to this day with his wife, Susan Gantner–also an expert in System i programming. Paris and Gantner, along with Paul Tuohy and Skip Marchesani, are co-founders of System i Developer, which hosts the new RPG & DB2 Summit conference. Send your questions or comments for Jon to Ted Holt via the IT Jungle Contact page.