rpg in v7 including the new free-form definitions. · jon paris jon.paris @ partner400.com rpg in...

32
Jon Paris Jon.Paris @ Partner400.com www.Partner400.com www.SystemiDeveloper.com RPG in V7 Including the New Free-Form Definitions. If you thought that RPGIV had changed over the years - well "You ain't seen nothin' yet!!" V7 brought with it a number of enhancements but the one that has made the biggest impact has undoubtedly been the introduction of free-form data and file definitions. Most of us have been making extensive use of Evals since they were first introduced with RPG IV in V3R1. Perhaps like us you have experienced frustration when forced to split a line because you had run out of space! Maybe you were even tempted to shorten that nice meaningful variable name to avoid having to use a second line! While you were contemplating this dilemma, you might have also noted the fact that there was a huge area of white space to the left of the Eval you couldn't use. V5R1 put an end to that frustration by introducing the notion of completely free-format logic specs. Coupled with a large number of new Built-In Functions (BIFs) this "New" RPG remains familiar, while offering some very powerful new capabilities. Then in V7.1 (with TR7) almost all the rest of the RPG language went free-format - with the addition of free-format replacements for H, F, D and P specs. In this session we will look at: How to code free format RPG logic How to replace operation codes that aren't supported in free format RPG The new BIFs that add power to the language New functions that only work in Free-form form logic How to use the free format replacements for H, F, D and P specs Notes © Partner400, 2016 Lecture Notes: Page 1 of 32

Upload: hakhue

Post on 20-Jul-2018

219 views

Category:

Documents


2 download

TRANSCRIPT

Jon Paris

Jon.Paris @ Partner400.com www.Partner400.com www.SystemiDeveloper.com

RPG in V7 Including the New

Free-Form Definitions.

If you thought that RPGIV had changed over the years - well "You ain't seen nothin' yet!!"

V7 brought with it a number of enhancements but the one that has made the biggest impact has undoubtedly been the introduction of free-form data and file definitions.

Most of us have been making extensive use of Evals since they were first introduced with RPG IV in V3R1. Perhaps like us you have experienced frustration when forced to split a line because you had run out of space! Maybe you were even tempted to shorten that nice meaningful variable name to avoid having to use a second line! While you were contemplating this dilemma, you might have also noted the fact that there was a huge area of white space to the left of the Eval you couldn't use.

V5R1 put an end to that frustration by introducing the notion of completely free-format logic specs. Coupled with a large number of new Built-In Functions (BIFs) this "New" RPG remains familiar, while offering some very powerful new capabilities.

Then in V7.1 (with TR7) almost all the rest of the RPG language went free-format - with the addition of free-format replacements for H, F, D and P specs. In this session we will look at:

How to code free format RPG logic ✦ How to replace operation codes that aren't supported in free format RPG ✦ The new BIFs that add power to the language ✦ New functions that only work in Free-form form logic

How to use the free format replacements for H, F, D and P specs

Notes

© Partner400, 2016 Lecture Notes: Page 1 of 32

Data Definition and Usage Enhancements Sort and Search Data Structure Arrays Support For Alias Names New Scan and Replace BIF Subprocedure related enhancements Prototypes are optional Performance improvements for large return values Process Stored Procedure Result Sets And of course free-form file and data definitions!

V 7.1 RPG Enhancements

NotesWe don't have time to go into all of these features in depth but we have written articles on many of them and of course you can find more about any that I skip by checking out the V7 RPG manual in the Information Center.

© Partner400, 2016 Lecture Notes: Page 2 of 32

D products1 DS Dim(999) Qualified D productCode 5a D description 40a Varying D totalSales 9p 2 D qtyInStock 5p 0

SortA products1(*).totalSales;

SortA products1(*).description;

SortA(A) products1(*).totalSales; // Sort ascending sequence

SortA(D) products1(*).description; // Sort descending sequence

Sorting Data Structure ArraysData structure arrays can now be sorted • Using any of the subfields as the key

✦ But only a single subfield can be used - No direct support for sorting multi-dimensional arrays

• Asterisk (*) identifies the level at which the array is to be sorted SORTA can now have sequence specified • Using the Op-code extenders A(scending) or D(escending) • Can only be used when no sequence specified in the D-specs

NotesWith the advent of V5R2, it became possible to define Data Structure arrays. i.e. with a DIM keyword at the DS level. But at the time IBM did not provide any means by which such arrays could effectively be sorted. To do that you had to resort to using the qsort function. That shortcoming is removed in V7 and you can now sort on any subfield in the array. For example, given the DS array here, you can perform a sort on qtyInStock or totalSales or any of the other fields in the DS. As you can see from this code, the level of the array to be sorted is indicated by an asterisk (*) in the subscript position.

In the first example the DS array is sequenced on the totalSales values, and in the second the description. Another nice addition to the SORTA repertoire is that you can now specify whether the sort is to be in ascending or descending sequence. Previously this was determined by the ASCEND or DESCEND keyword on the array definition and SORTA used the defined sequence - which of course meant that without playing games (re-mapping the array via pointers etc.) any given array could only ever be in ascending _or_ descending order. Now the op-code extenders (A) and (D) can be used to specify the sequence in which the array is sorted.

The * is used to indicate the level at which the sorting should occur. Of course, in these examples, it's pretty obvious, since it's the only level where sorting is possible. But this sorting capability also works with nested Data Structures, so even very complicated structures can be sorted. The next chart shows you how.

© Partner400, 2016 Lecture Notes: Page 3 of 32

D products2 DS Dim(999) Qualified D productCode 5a D description 40a Varying D salesByMonth LikeDS(salesByMonth) D Dim(12) D qtyInStock 5p 0 D salesByMonth DS D monthNumber 3p 0 D sales 9p 2 D i S 5i 0 // Sort each entry in turn into sales value sequence For i = 1 to %elem(products2); SortA products2(i).salesByMonth(*).sales; EndFor; // Once individual entries have been sorted into sales value // sequence sort the whole array into product code sequence SortA products2(*).productCode;

Sorting Nested Data Structure ArraysAs noted earlier - no direct RPG support exists • But this is one way to do it

NotesEven nested arrays can be sorted as shown in the example below. In this case the inner array (i.e. the monthly sales values) is sorted into ascending sequence and then the outer array (i.e. the products) are sorted into product code sequence. Of course, it doesn’t really matter which version of SORTA statement is done first - i.e., we could have sorted by ProductCode first, followed by the loop to sort the sales figures. Note, however, that there is still no support to sort on 2 (or more) different subfields in a DS array, unless the 2 subfields are contiguous in the DS and in the “correct” sequence.

© Partner400, 2016 Lecture Notes: Page 4 of 32

D productInfo DS Dim(1000) D Qualified D productCode 5a D description 40a D unitPrice 5p 2 D qtyInStock 5p 0

D element S 5i 0 element = %LookUp( 'A123C': productInfo(*).productCode);

// Sort into price sequence and then find first value above $50.

SortA productInfo(*).unitPrice;

element = %LookUp( 50.00: productInfo(*).unitPrice);

Searching DS Arrays%LOOKUP can now also search DS arrays • The same asterisk (*) notation is used to indicate the search level

Only the vanilla %LookUp is supported • Not the %LookUpGt etc. versions

NotesTo be truly useful, any enhancement in sorting needs to be matched with corresponding advances in searching, and the RPG developers haven't let us down. They have enhanced the %LOOKUP BIF to allow for searching within DS arrays. At this time only the "exact match" %LookUp is supported. Hopefully %LookUpGt and other members of the family will be supported in future releases. In the meantime you will have to write your own routine to do this.

© Partner400, 2016 Lecture Notes: Page 5 of 32

DDS for file CUSTFILE A R CUSTREC A CUSTNM 25A ALIAS(CUSTOMER_NAME) A CUSTAD 25A ALIAS(CUSTOMER_ADDRESS) A ID 10P 0

D custDs e ds ALIAS QUALIFIED D EXTNAME(custFile)

custDs.customer_name = 'John Smith'; custDs.customer_address = '123 Mockingbird Lane';

custDs.id = 12345;

Using ALIAS NamesALIAS names can be used in Externally-described data structures • By using the ALIAS keyword on the DS definition

ALIAS names can be used for file fields • Use the ALIAS keyword on the File specification

✦ Any LIKEREC or EXTNAME DS based on the file will use the ALIAS name

NotesFor many, many years going all the way back to the System/38, the database has supported the use of longer alias names as an alternative to the cryptic 10 character names that we normally use. Indeed many COBOL shops have always taken advantage of them. Usage of alias names has also increased in recent years with the growth in popularity of SQL. But during all this time RPGers were locked out of using these longer names as the language was tied to the old I and O specs and their limited field names.

When result field I/O was first introduced for externally described files - back in the V5R2 timeframe - we felt that this might herald the arrival of Alias names into RPG. Well it has taken a few releases, but it is finally here. As from V7.1 you can specify the ALIAS keyword when defining an externally described DS, or any DS defined with LIKEREC. When the ALIAS keyword is used, the compiler uses the longer alias name for the field rather than the short name. In cases where the alias name does not meet RPG naming standards, the compiler reverts to using the short name.

Note that you put the ALIAS keyword on the F spec if you choose to create the DS using LIKEREC. However, if you create the DS using EXTNAME, then use specify ALIAS on the DS description on the D spec.

© Partner400, 2016 Lecture Notes: Page 6 of 32

string1 = 'See &NAME. See &NAME run. Run &NAME run.';

string2 = %ScanRpl('NAME' : 'Forrest' : string1);

// string2 now contains 'See Forrest. See Forrest run. Run Forrest run.'

string3 = %ScanRpl(' ' : ' ' : string2); // Change double spaces to single

// string3 now contains 'See Forrest. See Forrest run. Run Forrest run.'

Scan and ReplaceNew built-in function %SCANRPL %SCANRPL ( scanFor : replaceWith : targetString ) • Replaces all occurrences of scanFor within the target string with the

contents of replaceWith ✦ Optional 4th & 5th parameters for scan-start-position and scan-length ✦ %SCANRPL( scanFor : replaceWith : target { : scan start { : scan length } )

Much simpler than having to code it the old way • i.e. a %SCAN and %REPLACE loop

✦ Or %Scan and %Subst or ...

NotesNote that in the example shown, replacing double spaces with a single space will only work on sets of double spaces on the first pass through the string. In other words, if there were 4 spaces in a row, the new string would still have 2 spaces. If there were 3 spaces initially there would still be 2 spaces after the replacement. But %ScanRpl can be used with a null string as the replacement - does that help? Well it does but it creates the problem that if there were originally an even number of spaces then after the replacement there are none! Since we don't know exactly where the spaces originally were, we have no idea where to put the required space back in. Sometimes it seems you just can't win. But we have shown a possible solution on the next page - it looks odd - but it works.

© Partner400, 2016 Lecture Notes: Page 7 of 32

d testString s 40a Inz('4 spc 7 spc 10+ spc ') d result s 40a Varying

/free

result = %ScanRpl( ' ': '<>': testString ); // replace each space with <> dsply ('Contents: ' + result );

result = %ScanRpl( '><': '': result ); // replace all >< with nothing

dsply ('Contents: ' + result );

result = %ScanRpl( '<>': ' ': result ); // replace remaining <> with space

dsply ('Contents: ' + result );

dsply ('Length of result is ' + %Char(%Len(result)));

Scan and Replace - ExampleThe code below will remove all instances of multiple spaces • And replace them with a single space

DSPLY op-codes allow you to see it happening step by step

NotesThis approach to the problem uses a rather strange looking sequence. It really does look "odd". For that reason I have included a number of displays so that you can see the change in the string as each phase progresses. I suspect there may be a better/shorter way of doing this but this one is fun anyway. If you decide to use it in a program PLEASE wrap it up in subprocedure or you will confuse the heck out of those who follow you!

Below you can see the displays produced:

DSPLY Contents: 4<>spc<><><><>5<>spc<><><><><>6<>spc<>

DSPLY Contents: 4<>spc<>5<>spc<>6<>spc<>

DSPLY Contents: 4 spc 5 spc 6 spc

DSPLY Length of result is 18

© Partner400, 2016 Lecture Notes: Page 8 of 32

D CustResultSet S SQLType(RESULT_SET_LOCATOR)

Exec SQL Call CustomersByState( :InputState );

Exec SQL Associate Result Set Locator (:CustResultSet) with Procedure CustomersByState; Exec SQL Allocate C1 Cursor for Result Set :CustResultSet;

Exec SQL Fetch next from C1 into :CustData;

Processing Result Sets in RPGRPG stored procedures have always been able to return a result set • But we could not receive/process that result set in an RPG program

This new support may feel a bit "clunky" - But it works - You need to ... • Define a RESULT_SET_LOCATOR (defined on D spec) • Then ASSOCIATE the Result Set Locator with the Procedure • Then ALLOCATE the CURSOR for the result set

NotesIf this syntax seems convoluted to you, we agree. It seems that it shouldn't need to be this complicated. But at least we can now receive and process result sets from a stored procedure in an RPG program. It was always incongruous that we could create the stored procedures that produced the result sets in RPG, but could not actually use those same stored procedures from an RPG program if we chose to.

Note that once you associate the result set locator and allocate the result set to a cursor, you can then simply fetch from that cursor as if it were a “normal” SQL cursor.

© Partner400, 2016 Lecture Notes: Page 9 of 32

Relaxed Prototype RequirementsPrior to 7.1, the compiler requires a Prototype when: • A subprocedure is compiled (even if called from a separate module) • A subprocedure is called (even if the subprocedure is in same module)

In 7.1+, Prototypes are optional in some specific cases • If the program or procedure is not called by another RPG module

✦ i.e. If not called from RPG, then the prototype will never be used • Examples of optional prototypes include:

✦ A program that is only intended to be used as an exit program or as the command-processing program for a command

✦ A program that is only intended to be called from a different (non-RPG) language ✦ A procedure that is not exported from the module (not callable externally) ✦ A procedure that is exported from the module but only intended to be called from a

different programming language

• In other words, if the compiler can get the parameter list from a PI in the same source member, the PR is optional

However, if you put the PR and the PI in the same source member, the compiler will validate the PR to ensure it is correct - Bonus!

NotesThe RPG compiler required prior to V7.1 that you have a PR in every source member where a PI for that procedure or program existed. The reason for this requirement was so that the compiler could validate that your PR was correct - i.e., that it matched your PI. This is good because if the PR matches, then all calls to that program or procedure will be validated by the compiler and parameter mismatches will be a thing of the past.

However, it was a bit painful that we had to put PRs in for cases where the PR would never be used by another RPGLE program - it was only called by CL or some other language that couldn’t use our prototype - likewise for internal subprocedures since the compiler could clearly get the parameter information directly from the PI, making the PR seem redundant.

You should still include the prototypes in any source members where external subprocedures are coded so that the compiler can check them for you. Use /Copy members for that purpose so that you can be sure that the version that was validated when compiling the subprocedures is the same one used by all the callers of those routines.

© Partner400, 2016 Lecture Notes: Page 10 of 32

D getFileData pr a Varying Len(1000000) D RtnParm D File a Const Varying Len(500) D Data S a Varying Len(1000) /Free Data = getFileData ('/home/mydir/myfile.txt');

New RTNPARM Prototype KeywordPerformance Boost for large return values • Converts the return value to a hidden parameter • Value reported by %PARMS( ) reflects the extra parameter

✦ But it will otherwise be "invisible" to RPG callers ✦ If calling from another language you will see the return value as the 1st parm

• Will improve performance when returning large values ✦ Especially very large varying values

Has a second unintended use • It allows subprocs with return values to be used by Java or stored

procedure ✦ Prior to this change you were limited to a 4 byte integer (10i)

D OptionalTest PI D Parm1 20A D Optional2 5P 0 Options(*NoPass)

D Parm2 S 5P 0 Inz(99999) // Check for optional parameter and use value if present If %ParmNum(Optional2) <= %Parms; Parm2 = Optional2; EndIf; If Parm2 .............

Better Support for Optional ParametersIn the past, checked %Parms for a hard-coded value • i.e., If %Parms > 1;

Now use %ParmNum( ) • Replaces hard-coded value for parm position • %ParmNum returns the sequence of the parameter in the parm list

In example below, %ParmNum(Optional2) returns 2 • i.e., Optional2 is the 2nd parameter declared in the PI

© Partner400, 2016 Lecture Notes: Page 11 of 32

V7 - TR7 Free Form EnhancementsEntire program can now be in free form - except I and O specs

§ No longer any need for /Free or /End-Free - Just leave columns 6 and 7 blank

New free form options for: § H-specs (CTL-OPT) § F-specs (DCL-F) § D-specs (DCL-xx)

- Where xx = C, DS, PARM**, PI, PR, S, or SUBF** • ** These are rarely going to be used

§ P-specs (DCL-PROC)

ctl-opt option(*srcstmt) dftactgrp(*No); dcl-ds employeeDS; firstName char(16) Inz('James'); lastname char(30) Inz('Joyce'); salary packed(7:2) Inz(12500); end-ds;

// Define printer file and associated DS dcl-f qprint printer(80); dcl-ds prtDs len(80) end-ds;

Not Technically a part of TR7 but was announced and released at

the same time

Completely free form logic brings RPG more in line with other modern programming languages, all of which use free format. This is important for attracting new developers coming into the marketplace.

Traditional fixed format RPG is far less attractive and gives RPG the undeserved appearance of an old-fashioned language not up to modern application tasks. RPG is a powerful and flexible language that many young developers come to prefer over other more popular language options for business applications.

But they must first be attracted to learn the language.

Notes

© Partner400, 2016 Lecture Notes: Page 12 of 32

ctl-opt option(*srcstmt) dftactgrp(*No); dcl-ds employeeDS; firstName char(16) Inz('James'); lastname char(30) Inz('Joyce'); salary packed(7:2) Inz(12500); end-ds; dcl-f qprint printer(80);

dcl-ds prtDs len(80) end-ds;

....

Format of the new DeclarationsAll of the new declaration op-codes follow this basic format:

§ First the DCL-xx itself § Next the name of the item

- File, field, procedure, etc.

§ Followed by keywords related to other fixed form elements - e.g. File usage, field type and length

§ Then keywords from the old spec We will be looking at a more complete code sample on the

next chart

Fixed column entries

From original D-spec keyword area

end-ds can be on the same line as dcl-ds in this case.

Notes

© Partner400, 2016 Lecture Notes: Page 13 of 32

ctl-opt option(*srcstmt) dftactgrp(*No); dcl-ds employeeDS; // Nice to be able to have comments here! firstName char(16) Inz('James'); lastname char(30) Inz('Joyce'); salary packed(7:2) Inz(12500); end-ds;

// Define printer file and associated DS dcl-f qprint printer(80); // This printer is program described dcl-ds prtDs len(80) end-ds;

dsply ('Hello to our new employee'); dsply ( %TrimR(firstName) + ' ' + lastName );

prtDs = 'The name of our new employee is ' + %TrimR(firstName) + ' ' + %TrimR(lastName) + ' his salary is $' + %Char(salary); write qprint prtds;

Simple Free Form ProgramFile definitions can be intermixed with data definitions

§ Named Constants, Data Structures, etc. Most new options have sensible defaults

§ Disk files default to input, Printers to output, Decimals to zero, etc. etc. End of line comments are now useful in definitions!

Note that the Printer is defined together with the DS that it uses for output

The idea of mixing file and data definitions will take some getting used to - but it makes sense.

After all it makes far more sense to define a set of variables, data structures and constants together with the file that they will be used with that to arbitrarily separate them as we had to before.

Notes

© Partner400, 2016 Lecture Notes: Page 14 of 32

CTL-OPT - The New H-SpecDefaults to DftActGrp(*No) if any ILE specific options are used

§ i.e. ACTGRP, BNDDIR, or STGMDL - This is the first of many "sensible" defaults that are added by this support

Only other differences are: § Can start in any column from 8 onwards § Must be terminated with a semi-colon § Presence of CTL-OPT stops compiler from looking for H spec data area

No other differences between this and the current H-spec § Can occupy multiple lines § Multiple CTL-OPT can appear in program

H BndDir('UTILBNDDIR') Option(*SRCSTMT: *NODEBUGIO)

Ctl-Opt BndDir('UTILBNDDIR'); Ctl-Opt Option(*SRCSTMT: *NODEBUGIO);

// Can also be coded as:

Ctl-Opt BndDir('UTILBNDDIR') Option(*SRCSTMT: *NODEBUGIO);

Not that much has changed about the H spec since it was almost free format before. Ctl-Opt replaces the H and the semi-colon is used at the end.

Notes

© Partner400, 2016 Lecture Notes: Page 15 of 32

FCUSTMR0 UF A E K DISK USROPN

FREPORT O E PRINTER OFLIND(*IN96)

FSCREEN CF E WORKSTN

Dcl-F CUSTMR0 DISK Usage(*Update:*Delete:*Output) Keyed UsrOpn;

Dcl-F REPORT PRINTER(*EXT) OFLIND(*IN96);

Dcl-F SCREEN WORKSTN Usage(*Input:*Output);

Declaring Files In Free-FormFile Name listed first - followed by device type keyword (if any)

§ Device type defaults to DISK - i.e., a Database table Externally described is the default

§ File Keyword *EXT can optionally be specified as a parameter Program described files must specify their record length

§ e.g. PRINTER(132) for a program described printer file Defaults for USAGE are based on device type - more in a moment

§ *Input, *Output, *Update (implies *Input), *Delete (implies *Update) Add KEYED keyword for keyed database (disk) files

In the example here, we have defined 3 files - one is a keyed database table (aka file), a report, and an interactive screen.

This example does specify some features that are not required. For example, PRINTER(*EXT) defining an externally described printer did not need the *EXT parameter since externally defined is always the default. Also the USAGE(*Input:*Output) on the Screen file is the default usage value for a display file and could have been omitted. Note that Usage(*Output) is implied by default for the Report file.

The OFLIND keyword on the Report file is “Overflow Indicator” which can be used by the program to determine when to go to a new page on the report.

There are other keywords that can be used when declaring files. These are the most commonly used features of file declarations.

The File name is no longer limited to 10 characters as it was on the F spec. However, since file object names (externally on the system) are limited to 10 characters, that means if a longer name is used, then keyword ExtDesc must be coded to give the real external name for the file. A longer, more meaningful name for the file may be useful for making the logic more readable.

Notes

© Partner400, 2016 Lecture Notes: Page 16 of 32

DCL-F - Helpful DefaultsFile name no longer limited to 10 characters

§ So meaningful file names can be used - EXTDESC is used to specify actual name when different from file name

Device type comes next followed by optional parameters § Device type can be omitted if using an externally described Disk file

- A sensible default

All defaults are based on device type § Usage(*Input) for DISK § Usage(*Output) for PRINTER § Usage(*Input : *Output) for WORKSTN

DCL-F InvoiceMaster ExtDesc('INVMAST'); // Defaults to Input Disk

DCL-F CustMaster Usage(*Update) Keyed; // Keyed Disk file

DCL-F qPrint Printer(132) OflInd(PageFull); // Program described

DCL-F MyDisplay WorkStn; // Workstation Usage(*Input : *Output)

Notes

© Partner400, 2016 Lecture Notes: Page 17 of 32

D Address DS Dim(20) Qualified D Street1 30A D City 30 D State 2 D Zip 5S 0 D ZipPlus 4S 0 dcl-ds Address Dim(20) Qualified; Street1 char(30); City char(30); State char(2); Zip zoned(5); // Zero decimals assumed ZipPlus zoned(4:0); end-ds Address;

DCL-xx - The New D-Specxx = DS for Data structures

§ In most cases there must also be a matching END-DS xx = SUBF for DS subfields - Very Rarely Required

§ Code only if field name is a valid free-form op-code - Yes some strange people do use names like READ or SELECT as field names

xx = S for Stand-Alone fields xx = C for Named Constants

DS Name optional at end Must match DS name

END-DS may be omitted if DS is externally described or has no named subfields. It can even be on the same line as the DCL-DS in such cases, such as the following DS which is externally described based on a table (aka file) named PRODUCT.

dcl-ds product Ext end-ds;

Name of DS can be specified on end-ds and must match if present.

Notes

© Partner400, 2016 Lecture Notes: Page 18 of 32

DCL-xx - The New D-Spec - Data TypesData types are spelled out instead of using a one character code

§ Chart below shows the most commonly used types § Length or format of item follows in parentheses when required

Simpler definition for some data types § VarChar avoids the need for the Varying keyword § Date, Time, Timestamp don't need separate DatFmt keyword § 0 (zero) decimals assumed for all numeric data types if not specified.

Data Type Free Keyword NotesA Char(len)A + Varying

Varchar(len)I Int(len) Decimals not specifiedU Uns(len) Decimals not specifiedP Packed(len:dec) 0 assumed if decimals not givenS Zoned (len:dec) 0 assumed if decimals not givenN IndD + DatFmt

Date(format)B BinDec

(len:dec)!! DO NOT USE !!

The following is a partial list of RPG data types represented as D-specs:

d packedNum s 7p 2

d zonedNum s 7s 2

d integer s 10i 0

d unsigned s 10u 0

d float s 8f

d character s 20a

d varyingChar s 20a Varying

d dateMDY s d DatFmt(*MDY)

d timeUSA s t TimFmt(*USA)

d indicator s n

d nastybinary s 9b 0

And here are their free form equivalents.

Dcl-S packedNum Packed(7:2);

Dcl-S zonedNum Zoned(7:2);

Dcl-S integer Int(10);

Dcl-S unsigned Uns(10);

Dcl-S float Float(8);

Dcl-S character Char(20);

Dcl-S varyingChar Varchar(20);

Dcl-S dateMDY Date(*MDY);

Dcl-S timeUSA Time(*USA);

Dcl-S indicator Ind;

Dcl-S nastybinary Bindec(9);

© Partner400, 2016 Lecture Notes: Page 19 of 32

D MyDS DS D Address 32A D Street 15A Overlay(Address) D City 10A Overlay(Address: *Next) D State 2A Overlay(Address: *Next) D Zip 5A Overlay(Address: *Next) D LstOrdDate D DatFmt(*USA) D ASubfield 25A Varying

Dcl-DS MyDs; Address Char(32); Street Char(15) Overlay(Address); City Char(10) Overlay(Address:16); State Char(2) Overlay(Address:26); Zip Char(5) Overlay(Address:28); LstOrdDate Date(*USA); ASubfield Varchar(25); End-DS;

D-Spec DS ExampleThis shows how a fixed form DS would be converted to free-form • I have used my own personal preferences for alignment

✦ At least they were my preferences at the time I coded this example!

I like the idea of aligning the field type definitions even though it is not required. I don't however insist on placing them in a specific column. Rather I start them 2 characters after the end of the longest field name in the block. For me it works but you'll devise your own style - just be consistent and remember that readability is critical.

Notes

© Partner400, 2016 Lecture Notes: Page 20 of 32

Dcl-DS DayData; *n Char(9) inz('Monday'); *n Char(9) inz('Tuesday'); *n Char(9) inz('Wednesday'); *n Char(9) inz('Thursday'); *n Char(9) inz('Friday'); *n Char(9) inz('Saturday'); *n Char(9) inz('Sunday');

DayArray Char(9) Dim(7) Pos(1);

End-ds;

D-Spec - Unnamed Fields and OverlaysIn fixed form no field name was required • In free-form we must specifically inform the compiler

✦ Done by coding *N instead of a field name

In free-form we are not permitted to OVERLAY the DS name • IBM decided that it should never have been allowed so they stopped it • So we must use POS(1) instead

✦ POS(nn) can also be used for positioning any field within a DS ✦ For example when specifying specific fields in the PSDS

The RPG compiler team decided that too many people got confused when the OVERLAY keyword was used against the DS name. To help avoid this confusion, OVERLAY is now limited to subfields within the DS and you must use the POS keyword to reference the DS starting position.

This is effectively the same as using a start position on the old D-specs.

This is what the DS would have looked like in fixed-form.

D DayData DS D 9 Inz('Monday') D 9 Inz('Tuesday') D 9 Inz('Wednesday') D 9 Inz('Thursday') D 9 Inz('Friday') D 9 Inz('Saturday') D 9 Inz('Sunday')

D DayArray 9 Overlay(DayData) Dim(7)

Notes

© Partner400, 2016 Lecture Notes: Page 21 of 32

D DateMDY S D DatFmt(*MDY-)

D array S 10a dim(10)

D CustomerInfo DS D CustomerName 50A Varying D CustomerBalance... D 7P 2

dcl-s DateMDY Date(*MDY-);

dcl-S array Char(10) Dim(10);

dcl-c Digits 7; dcl-c Decimals 2;

dcl-ds CustomerInfo; CustomerName VarChar(50); CustomerBalance Packed( Digits: Decimals); end-ds;

More on Data DefinitionConstants can be used in many more places • Including field length, decimal places, array dimensions - just about

anywhere you would use a literal Long names don’t require ellipsis … and a continuation line

Constants can be used for length definition. Makes it really easy to change all currency fields from say 7,2 to 9,2 !!!

Note that in the fixed format example here, it made no sense to define Digits and Decimals as constants since they could not be used to define the length and precision in fixed format D specs. However, in the new free format D specs, they can be used - as illustrated in the 2nd example.

Note that not only are the ellipsis not required for longer variable names - they are not allowed in most cases. Unless the actual variable name is continued on the next line, ellipsis should not be used, even if the data type and other related keywords are on the next line. If ellipsis are found, the compiler assumes the next line will contain part of the variable name.

Notes

© Partner400, 2016 Lecture Notes: Page 22 of 32

D myDataArea ds DtaAra(JonsData) D lastRunDate d DatFmt(*USA) D lastSeqNum 5i 0 D lastInvNum 7p 0

Dcl-Ds myDataArea DtaAra(JonsData); // Wrong unless // JonsData is a constant

Dcl-Ds myDataArea DtaAra('JONSDATA'); lastRunDate Date(*USA); lastSeqNum Int(5); lastInvNum Packed(7); End-Ds;

Data Areas This is an area where you may trip up • D specs only allowed literals - constants were not allowed

✦ So quotation marks were not compulsory

• Now you will probably get a compiler error if you forget the quotes ✦ It will be looking for a constant named JonsData

• And of course you must specify the name all in upper case

This is one of a number of similar areas where previously the compiler only allowed a literal - so even if quotes were not used the compiler just assumed them and was quite happy.

This new support though allows for far more widespread use of constants and subsequently where literals are used they must _be_ literals - complete with quotes and the data in the right case.

With great power comes ...

Notes

© Partner400, 2016 Lecture Notes: Page 23 of 32

Subprocedures, Prototypes and More

dcl-proc DayOfWeek Export;

dcl-pi *N Int(3) ExtProc(*DclCase); // Omit name - use *N placeholder InputDate Date(*USA) Value; end-pi;

dcl-s DayNumber int(3); // Do calcs leaving value in DayNumber Return DayNumber;

end-proc DayOfWeek;

DCL-PROC declares a subprocedure • Completed by an END-PROC

DCL-PI and DCL-PR define procedure interfaces and prototypes • Placeholder *N can be used if you don't want to type the name again • DCL-PARM is the optional equivalent of DCL-SUBF within PIs and PRs

✦ Only needed if name of parameter is the same as an RPG op-code

New option for EXTPROC - *DCLCASE • Means the real name is exactly the same as the procedure or prototype name

✦ Avoids having to retype the name when using mixed case procedure names

The biggest advantage of the new support is that you no longer have to flip in and out of fixed and free modes when coding subprocedures. No more /End-Free, P-specs, D-Specs, /Free, logic, /End-Free etc. It makes it all look much cleaner and removes a major source of mistakes (and frustration) for those learning RPG.

Notes

© Partner400, 2016 Lecture Notes: Page 24 of 32

Subprocedures, Prototypes and More

dcl-pr MyProgram; // Used to call 'MYPROGRAM' from non-ILE program

dcl-pr MyProgram ExtPgm; // Calls 'MYPROGRAM' from any program

dcl-pr DifferentName Extpgm('MYPROGRAM'); // Call 'MYPROGRAM using the // name DifferentName

EXTPGM keyword can be omitted • Providing that the program is non-ILE i.e. DFTACTGRP(*YES)

Program name can be omitted from EXTPGM • If the program name is the same as the prototype

EXTPGM('PROGNAME') • Parameter only needed when proto name is different from actual program

name

Once again the new support adds some sensible and useful defaults.

The more I use this stuff the more I love it!

Notes

© Partner400, 2016 Lecture Notes: Page 25 of 32

Converting to Fully Free FormIBM does NOT supply a tool to do this

§ Even RDi's free-form converter has not been updated

Currently we know of three tools that are available § Linoma's RPG Toolbox (linomasoftware.com/products/rpgtoolbox)

- Which also does a great job of converting old-style fixed-form to free form - More in a moment

§ Arcad Transformer (arcadsoftware.com) - A far more all-embracing modernization tool - but more expensive

• Details at arcadsoftware.com/products/arcad-transformer-ibm-i-refactoring-tools/ - It can even refactor code to the extent of getting rid of GOTOs and other similar

ancient constructs.

§ Craig Rutledge's Free Tools (www.jcrcmds.com) - An addition to Craig's previous free-form conversion tools - Complete H, F and D spec conversion

We have been using Linoma's conversion tool since way back in the V3 days when RPG IV was first introduced. Over the years they have steadily added more and more functionality including the ability to apply "aggressive" conversion options that deal with converting various flavours of MOVE operations.

With the latest updates they also introduced a low-cost add on to the toolbox that works as a plug-in to RDi and does a great job of converting whole prong ams or just selected pieces.

Another nice feature, not related to free-form, is an indenting option that re-establishes correct indentation after you have changed the structure of an If, For, Dox, etc. block.

Arcad's tooling is more recent but much more all encompassing. I like what I have seen of it but have not had any long-term experience with the tool.

Notes

© Partner400, 2016 Lecture Notes: Page 26 of 32

Linoma's RPG ToolBox - Side By Side Comparison

Linoma's tool does a great job but ... § It tends to play it safe and includes a lot of extra keywords § I'm also not a fan of the way it aligns things - it doesn't!

- But they are looking at changing this and providing more formatting options

BeforeAfter

My biggest grouse with the Linoma tool is that it converts everything and that means it also adds a bunch of file declaration keywords that are not necessary. The first thing I do after running a conversion with the tool is to manually clean it up.

Their conversion of D-specs does not apply any alignment to the resulting code - just inserts a single blank between the components. For me the result looks messy so again I apply some manual clean up after conversion. An example on the next chart.

Notes

© Partner400, 2016 Lecture Notes: Page 27 of 32

Edited Version of Converted CodeI removed the superfluous file entries and applied my own alignment

style to the data declarations.

Here you can see that I have removed the superfluous keywords from the file declaration. I have also added some alignment to the data declarations.

Right now my basic alignment rule is that in any given group (i.e. DS, PR, PI, series of standalone fields, etc.) I insert two spaces between the longest data name in the group and its data type/length definition and then align all other entries in the group to that. You can see the effect in the chart.

Note that I don't try and make all the entries in all the groups align - that is just too much work and I don't find it necessary - but visually I do like the entries in a specific group to align.

Choose your own style - but try to make sure that everyone in the shop uses the same (or very similar) style.

Notes

© Partner400, 2016 Lecture Notes: Page 28 of 32

Time to Update Your EditorThis is what free-form coding looks like in SEU

§ IBM will NOT be enhancing SEU to handle these new definitions Time you moved up to a real editor - RDi

IBM has confirmed that SEU will not be updated to support this new functionality. In fact it was frozen as at V6 and supports none of the V7 functionality.

As a result a great many people have started doing what they should have done many years ago and moved their development to RDi. It fully supports the new free-form including excellent code-assist to help you remember the new formats.

Notes

© Partner400, 2016 Lecture Notes: Page 29 of 32

"Gotchas" to Watch Out ForOVERLAY keyword cannot be used against DS name

§ Use POS(n) instead Names in EXTNAME, EXTFLD, and DTAARA

§ Must be in quotes and are case sensitive § Without quotes, they are treated as a variable or constant name

Ellipsis (...) for continuation only allowed when continuing a name § But not really needed anymore anyway

On F-Spec "U" enables update and delete § In free form *DELETE must be requested explicitly

End-DS, End-PR, End-PI are always required § But may appear on same line as DCL-xx in some cases

RDi's "Convert all to Free-Form" means only convert "all logic" § And will still generate /Free and /End-Free

I and O specs remain in fixed form § Probably forever

Notes

© Partner400, 2016 Lecture Notes: Page 30 of 32

The High PointsIntelligent defaults

§ For device type (Defaults to DISK) § Usage (Default based on device type) § Decimal places (Defaults to zero)

Constants can be used as keyword values § Including for lengths and decimal places

DFTACTGRP(*NO) is optional § If any other ILE keyword such as ACTGRP or BNDDIR is used

File and data declarations can be mixed § Even in fixed form

/Free and /End-Free no longer required

/Copy and other compiler directives no longer need to start in col 7

// style end of line comments can be used in data/file declarations

Notes

© Partner400, 2016 Lecture Notes: Page 31 of 32

Resources

Articles by Jon Paris and Susan Gantner • Search for them from the IBM Systems Magazine site

✦ www.ibmsystemsmag.com/authors/Susan-Gantner/ ✦ www.ibmsystemsmag.com/authors/Jon-Paris/

Free-Format RPG IV: Third Edition ✦ by Jim Martin ✦ Published by MCPress (www.MC-store.com) ✦ Make sure to order the third edition - older versions do NOT contain the V7 free-form

additions

As noted on the chart - if buying Jim Martin's book make sure you get the third edition or later. The earlier versions do not include the V7 enhancements that we have been discussing in this session.

Notes

© Partner400, 2016 Lecture Notes: Page 32 of 32