Do-It-Yourself Data Types
September 16, 2009 Jon Paris
I still fondly remember that “ah-ha!” moment many years ago when I was first introduced to the S/38 and discovered the joys of the consistency that resulted from centrally described data items and the ability to define a new field as looking like another. While other languages I had worked with, such as COBOL, had copy directives that allowed you to bring in standard definitions, the S/38 was the only machine I had come across where such ideas were built into the actual system itself and all of the compilers took advantage of them in one way or another. RPG/400 introduced the notion of externally described data structures, but sometimes they just aren’t enough. For the longest time there were no significant RPG enhancements in this area, but that era came to an end in V5R1 when RPG’s data definition capabilities started to “grow up.” In fact, by the time V5R2 was released, we did indeed have the ability to define our own data types. V6R1 (or 6.1 if your brain has been converted to the new numbering style) rounded out the new support by adding the TEMPLATE keyword. For those of you not yet on 6.1 we’ll discuss your options later. TEMPLATE allows us to define a field, file or data structure as a cloneable data type, complete with custom initialization values, without wasting any storage. Let me show you what I mean. In the example below, I have defined “address” as a template data structure. I can’t store data in it, but I can specify custom initialization as demonstrated by the INZ keywords. I then defined two new structures, “shipAddress” and “mailAddress,” based on the address DS. D address ds Template Inz D line1 40a D line2 40a D city 30a D state 2a Inz('MN') D shipAddress ds LikeDS(address) D mailAddress ds LikeDS(address) /free If ( shipAddress.state = mailAddress.state ); Since LikeDS() clones all the fields in the DS, each of the new structures contains “city” and “state” fields. Of course, we can’t reference them simply by using those names; the compiler would have no way of knowing which one we meant. The way to reference the fields is as shown in the “If” statement, i.e., by using the field’s qualified name. Some people claim that the qualified data names are cumbersome, and involve too much typing. To them I can only say, “horse hockey.” The additional benefit of knowing how the data is structured and stored is more than adequate compensation. Besides, using Remote Systems Explorer in WDSC or RDi (SEU is so 1980) allows me to select the appropriate name from a prompt list, so I really don’t have to type much, and that in turn means fewer spelling errors. If you are still not convinced, think of this. You only have to type things once–you will have to read them over and over and over again. Isn’t it important to get as much information from each reading as possible? That is certainly something I appreciate more as my grey cells get older and fewer in number. Couldn’t I have used an externally described DS in this case and simply prefixed the field names to avoid the duplication? Yes, in this specific instance, but with qualified names I don’t have to mentally decode some arbitrary prefix that somebody made up several years ago. Which is easier to understand? SASTATE or shipAddress.state? It is easy to get stuck and continue to limit our solutions to the tools that have traditionally been available to us. So sometimes we need to step back and look at new capabilities to see how we can exploit them. Here’s an example of a single structure that contains a lot of nicely organized information. As you can see, an externally described data structure simply couldn’t achieve this, no matter how hard you might try. D phoneNumber ds Template D areaCode 3s 0 Inz(507) D number 7s 0 D custInfo ds Qualified D customerName 30a D contactName 30a D phone LikeDS(phoneNumber) D Inz(*LikeDS) D fax LikeDS(phoneNumber) D Inz(*LikeDS) D shipAddress LikeDS(address) D Inz(*LikeDS) D mailAddress LikeDS(address) D Inz(*LikeDS) In this example, note how the two addresses have been included in the “custInfo” structure. In addition I have incorporated “phone” and “fax” numbers, each of which is based on the new “phoneNumber” template. Not only that, but in the example I have used the additional INZ keyword option *LIKEDS, which causes the compiler to use the initialization defaults specified on the template. In case you are wondering, the two “state” fields would now be referenced as shown here: If ( custInfo.shipAddress.state = custInfo mailAddress.state ); And the “areaCode” part of the fax number is referenced as “custInfo.fax.areaCode”. It is that simple. Aren’t self-explanatory data names great? Two things before I close. First, if you really want to exploit these capabilities, it would be a good idea to gather together your commonly used templates and place them in a copy member that you could include easily in all of your programs. Since the templates take up no memory space (they are just used by the compiler), including them makes it easy to access standard definitions in all of your programs with no cost in memory of efficiency. Second, I said I would deal with the issues faced by those of you who are not yet on 6.1. The only keyword that is not available to you is TEMPLATE. You can use all of the other features that I have discussed. So what is the impact of this? There are two issues.
Neither of these are show stoppers, however. I have been using DIY data types since they were first introduced. For me the TEMPLATE keyword simply removed some of the issues surrounding their use. So, give it a try–you have nothing to lose but your old habits. And you’ll be amazed at how much shorter your programs can be when you can tap into a set of standard definitions to do a lot of the D-spec work for you. You’ll also benefit from improved maintainability through the use of standardized names. And, of course, should there ever come a day when we need four-digit area codes in our phone numbers. . . 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 Summitconference. Send your questions or comments for Jon to Ted Holt via the IT Jungle Contact page.
|
How can I do a chain (not into DS) and then get the contents of the record into a DS? I am trying to avoid changing all the field assignments into qualified names in an existing program that updates the record I am chaining to. Want to capture the before and after picture of the record by passing the DS to an external procedure.