Of course D-specs are also the vehicle by which we define prototypes and procedure interfaces. I’ll be dealing with those in more detail in a future tip, but for the sake of completeness the declaration types used are:
If you read the manual you will also see that there is also a dcl-subf for the definition of DS subfields but this will normally be omitted in much the same way as we omit EVAL in calcs. The only time it is required is when the field name matches that of an existing op-code.
Next comes the field name, optionally followed by the data type and length definition. These are followed by optional keywords, which for the most part are the same as they were on the old D-specs.
In other words the sequence of elements is basically the same as in the old D-specs. Name then type/length, followed by options. I found it useful to keep this in mind while learning the ropes of the new specifications.
Time for some examples. Let’s start with a basic DS array and see how it translates.
d Address ds Dim(20) Qualified d Street1 30a d Street2 30a d City 30a d State 2a d Zip 5s 0 d ZipPlus 4s 0
This is the same structure built using the new notation:
dcl-ds Address Dim(20) Qualified; (1) Street1 char(30); Street2 char(30); City char(30); State char(2); (2) Zip zoned(5); ZipPlus zoned(4); (3) end-ds Address;
There are three points highlighted here.
First, the old 30a length definition has been replaced by the more meaningful char(30). A similar thing has happened with the 5s 0 definition, which is now replaced by zoned(5). As you can see there is no need to specify the number of decimal places when there are none. I really like that.
Last but not least, you can see (3) the end-ds that completes the DS. At first I wasn’t thrilled about having to code this, but now that I’ve used it I find I like the fact that it provides a definitive end to the structure. Also now that RDi has been updated to support the new syntax I can opt to have it automagically type the end-ds for me so it doesn’t force me to do any more typing. The name of the DS has been included here in much the same way as the name can be repeated on the end markers of subroutines and subprocedures. It is not compulsory but can be useful when navigating through the code.
The one time when you don’t need an end-ds is when defining a DS using LikeDS. This makes sense since no subfields can be defined within such structures.
To avoid having to code an additional line when specifying a DS with no defined subfields the rules are relaxed to allow the end-ds to be coded on the same line as the dcl-ds. This applies to externally described DS and to any DS with a length definition, but no subfields, as shown in the examples below.
dcl-ds product Ext end-ds; dcl-ds NoFieldsDS Len(100) end-ds;
Much as I like this new support, one thing I am still wrestling with is how best to align the various ele-ments. The only place I used to have to worry about that was how to indent the field names. It doesn’t feel quite right to line up the subfield names under the DS name–that ends up leaving too much wasted space on the left-hand side. At the moment I have settled on using the style you see in these examples, but I reserve the right to change my mind at any time! I do find it essential to align the type/length definitions and have customized the tabs in my RDi configuration to facilitate this.
Having looked at a basic example, let’s look at a couple of the less frequently used DS capabilities and how they translate. This example takes advantage of the fact that you do not need to name fields in a DS to provide an alternative to compile time arrays, which I have always disliked.
D Messages DS D 20a Inz('Invalid Item Code') D 20a Inz('Too many selections') D 20a Inz('Item Code required') D 20a Inz('Huh?') D Msg 20a Overlay(Messages) Dim(4)
Notice that in the new version we have to use the *N placeholder for the name–we cannot simply omit the name as we did in the old version. The other significant difference is that we are no longer permitted to use the Overlay keyword against a DS name. Instead we use the new POS keyword, which is the equivalent of the old From column. This is the result:
dcl-ds Messages; *n Char(20) Inz('Invalid Item Code'); *n Char(20) Inz('Too many selections'); *n Char(20) Inz('Item Code required'); *n Char(20) Inz('Huh?'); Msg Char(20) Dim(4) Pos(1); end-ds;
One other notable change is that, in some situations, data attributes that were formerly designated by keywords are now incorporated into the definition. This is one of the advantages of being able to use more than a single column for the data type. For example, the data type VarChar is now used instead of defining the field as character (Char) and then adding the Varying keyword. As the example also shows, date fields no longer require the DatFmt keyword–the format is now incorporated as a parameter to the data type itself. Time fields are treated in the same way. Similarly, to define a procedure pointer we add the *PROC parameter to the pointer data type.
So these definitions:
d CSVString s 5000a Varying d DateMDY s d DatFmt(*MDY-) d MyProcPtr s * ProcPtr
dcl-s CSVString VarChar(5000); dcl-s DateMDY Date(*MDY-); dcl-s MyProcPtr Pointer(*PROC);
The RPG team also took a similar approach with named constants. So that this:
d ActiveAccount c 'A' d InactiveAccount. d c Const('I')
Becomes this in the new format:
dcl-c ActiveAccount 'A'; dcl-c InactiveAccount Const('I');
Personally I’ve never used the CONST keyword–it always felt as if I was saying it was a constant constant since the C already designated it as a constant definition. But I guess I’m in the minority because most code I see uses CONST. At least the new version looks better.
One of the benefits of the new format that I could have mentioned in the previous tip is also apparent here in that a continuation line is not required in order to accommodate the long constant name. It would have to be a really long name before the ellipses were required!
One thing that I had expected to disappear with the advent of the new format was the ability to embed constants into a DS. Not sure why, but it always felt like an accidental feature rather than a deliberate design. But it is still there . . . and still looks a bit strange. Here’s a before and after example to show you what I mean.
d CustomerDetail ds d CustomerType 1a d Retail c 'R' d Wholesale c 'W' d Government c 'G' d CustomerName 50a Varying dcl-ds CustomerDetail; CustomerType Char(1); dcl-c Retail 'R'; dcl-c Wholesale 'W'; dcl-c Government 'G'; CustomerName VarChar(50); end-ds;
Well that’s about it for this tip. There’s a lot more that we could say about data definition in the new for-mat, but we have to stop somewhere. In subsequent tips we’ll look at the new ways to define control specifications (the H-spec), file definitions, prototypes and procedure interfaces.
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.
Post this story to del.icio.us
Post this story to Digg
Post this story to Slashdot