Top 10 Things RPG Needs

RPG
Typography
  • Smaller Small Medium Big Bigger
  • Default Helvetica Segoe Georgia Times

It's sort of a habit with me: Every few years, I create a list of things I'd like to see added to RPG. I normally post it on my Web site or publish it in an email to IBM Canada. Lately, however, I've been thinking that there really aren't 10 things I'd like to see added to RPG IV--rather, these are things that I think need to be added to or changed in the language.

So I've created this hybrid list of a few new features and a few changes. When I consider new features, I don't consider what it is I'm working on this week and need (the issue of the moment), but rather the long-term impact the feature would have to the language. So while I would really love to have something like a built-in function that reads comma-separated values into RPG, in the long run, that's probably not going to do me too much good. After all, how many times will I need to write a routine to read CSV files versus how many times I'll need something like CGI features in an application?

So here they are in no particular order, the top 10 features I'd like to see added to or changed in RPG IV:

  1. Built-in FTP capability via a %FTP() built-in function
  2. Case-insensitive %SCAN built-in function (maybe %SCANI() would do it?)
  3. Elimination of SEU as the default editor from the operating system
  4. Find and Replace built-in function
  5. Consistent implementation of new features
  6. Integrated support for CGI-related features and functions
  7. Integration with embedded SQL
  8. Language-independent character conversion routines--%ToUpper() and %ToLower()
  9. Overloaded procedure parameters
  10. Recognition of // as comments on any line without a character in column 6

Let's look at each one of these in more detail.

Built-In Support for FTP

I would love to have a %FTP() built-in function as part of RPG. How many times have you needed to get a file from another system and had to write an FTP script and then call a CL program to run that FTP script? Why not just allow the RPG program to do the work? This would require a few new built-in functions, perhaps something like the following:

ftp-handle = %FTPOpen( IP-address or domain : UserID : Password )
%FTPGet( ftp-handle : remote-file : local-file : *REPLACE )
%FTPPut( ftp-handle : local-file : remote-file : *REPLACE )
%FTPDir( ftp-handle : returned-list-of-files-in-directory )
%FTPCmd( ftp-handle : ftp-cmd )
%FTPReply( ftp-handle : ftp-reply-code-text )
%FTPClose( ftp-handle )

The idea is that you would open an FTP connection using the %FTPOpen built-in function. The %FTPOpen function would return a handle to the FTP session. That handle would then be used on all subsequent FTP built-in functions. This would allow multiple FTP sessions to be opened and processed at the same time.

Most of the FTP built-in functions listed above are self-explanatory. For example, the %FTPGet() and %FTPPut() built-in functions would be used to receive and send files, respectively. The %FTPDir() built-in function would generate a list of file names in the current working directory and return that list to the second parameter. The %FTPCmd() built-in function would allow any FTP command to be run, such as CD, RCMD, etc. The %FTPReply() built-in function would retrieve the reply code and text associated with the previous FTP command. Obviously, %FTPClose would close the FTP connection.

Case-Insensitive Scan

It is a pain to deal with upper/lowercase and the issue of language character sets, such as CCSID codes. We need a simple, case-insensitive scan function. This should be identical to %SCAN in syntax, but it should scan without concern for upper/lowercase. I'm suggesting %SCANI be used so that it can be easily plugged into existing code where it is needed.

Elimination of SEU from the Operation System

This is getting to me more and more lately. As most of you know, I wrote my own RPG editor for Windows (CodeStudio) way back before IBM ported CODE/400 to Windows. I continue to use it to this day. But I'm not advocating using CodeStudio over CODE/400 or vice versa. IBM and I have been doing that for years, and it just hasn't worked; most people still use SEU.

What I am advocating, however, is that IBM stop enhancing SEU and, in fact, stop automatically installing it with OS/400, beginning with OS/400 Version 6. The only way to get RPG programmers to move to CODE/400, Eclipse, or CodeStudio is to make using SEU more difficult.

Why do I advocate this? SEU is severely holding back the RPG development community. SEU may be a good fallback editor for quick and dirty jobs, but that is only true if you are not used to using one of the new editors. For more information on this topic, see "The Midrange Manager" in this issue.

Find and Replace Function

Currently, there are two functions you can use to search for and replace character fields in RPG. The first is %SCAN, and the second is %REPLACE. Using %SCAN is fairly simple, but using %REPLACE is, at best, complex. What would be helpful is an integrated find/replace function that combines these two functions. Something like this:

%FINDREPLACE(  find-text : replace-text : text-to-search : options )

Here, find-text is the text to be located, replace-text is the text to replace the find-text, text-to-search is the text being searched, and options is one or more controls. For example, options could be omitted, and the function would do a simple find/replace. Or options could be replaced with any one of the following: *MATCHCASE to cause a case-sensitive find/replace action, *NOCASE to cause a case-insensitive find/replace action (the default), *WORD to cause the find/replace action to match whole words only (no partial words), or *WILDCARD to indicate that the find-text parameter contains generic or "wildcard" characters. In addition, there should be an option to replace either just the first occurrence of the find-text or all occurrences, e.g., *ALL (the default) or *FIRST.

Also the length of the find-text and the replace-text should not need to be the same. The data would be automatically shifted within the text-to-search. So, for example, the following would work the way you'd expect it to:

%FindReplace( 'Midrange Computing' : 'MC Press' : Articles : *ALL)

All occurrences of "Midrange Computing" would be replaced with the words "MC Press" in the field named Articles.

New Feature Consistency

This is something that pains me in each new release. Due to legacy implementations and to a lesser extent, insufficient planning, new features are finding their way into RPG without IBM's taking into consideration existing features or potential future enhancements. Consequently, we end up with inconsistent keyword syntax and redundant functionality. Probably the biggest oops in this area is the implementation of Definition specification keywords.

Definition specification keywords that utilize literals such as those that need a file name or data area name are now being enhanced to support the use of a field name to contain those values.

For example, the DTAARA(MYDTA) and DTAARA(*VAR : MYDTA) keywords use two completely different syntaxes. In the first (original) syntax, MYDTA is the actual name of the data area. Unfortunately, it does not allow a data area to be qualified to a library name, nor does it allow a field name to be specified that contains the name of the data area.

Then, in V5R2, IBM introduced a new syntax that allows a field name to contain a data area name. In order for the compiler to know that the field name is a field name, IBM had to create a new syntax. Consequently, we have an alternate syntax for the DTAARA keyword: DTAARA(*VAR : MYDTA). The *VAR value indicates that the value of the second parameter is a field name that contains the name of the data area you want to read.

If it had been up to me, I would have circumvented this legacy flaw by simply creating a new keyword, perhaps EXTOBJ (external object), and allowed only a variable name or a quoted name to be specified for the first parameter. The second parameter would, of course, contain the object type so that other objects could be read into RPG just as easily as a data area is. For example, why not support EXTOBJ( myobj : *USRSPC), where myobj is a field containing a qualified object name and *USRSPC is the object type? This would allow us to easily read the contents of a user space object as well as any other object that may fit this design model.

Another inconsistency that seems troublesome is the use of record format names for some operations and built-in functions and file names for others. Database record names have not become an industry standard, and multi-format files are taboo. So why not allow us to specify either record format names or file names, and why not allow a record format name to be the same as a file name? That way, I wouldn't end up with code that looks like this:

.....FFileName++IFEASFRlen+LKeylnKFDevice+.Functions++++++++++++++++++++++++++
     FCustMast  UF   E           K DISK    RENAME(CustMast : CustRecUSROPN

.....CSRn01..............OpCode(ex)Extended-factor2+++++++++++
     C                   if        NOT %Open(CustMast)
     C                   Open      CustMast
     C                   Chain     CustRec
     C                   if        %Found(CustMast)
     C                   Eval      BalDue = 0
     C                   Update    CustRec
     C                   endif
     C                   endif

Integrated Support for CGI Functionality

I know this kind of thing is not popular with the RPG developers at IBM Canada, but I think it is necessary and critical to the survival of the language. Most other languages have integrated support for CGI programming, or they have extensive runtime libraries that provide essentially the same thing. RPG has neither and yet is one of the best languages to use for CGI programming.

What is needed to support CGI is the ability to retrieve data from an HTML form on a field-by-field basis, the ability to encode (that is escape) a text string such as a URL or HTML that is being sent to a browser session, and the ability to un-escape those same strings when they are read into RPG. Going overboard, there could also be functions to simplify the writing of HTML to the browser. This would require built-in support for writing to the standard-output device, including automatic detection of special character sequences, such as .

Better Integration with SQL

Do I even need to explain myself here? What I am proposing is that the SQL statements or commands be integrated with the RPG language. That is, from an RPG programmer's perspective, using SQL statement syntax would be no different from using the CHAIN opcodes in the new free-format syntax. You would just start a new line--no "C" or anything else in column 6 and no ridiculous plus sign (+) in column 7--and then code the SQL statement. And if the compiler detected the FETCH statement, it would assume you wanted the SQL Fetch statement. Consider the difference between parsing the SQL FETCH statement vs. using a procedure named FETCH--nothing could be more complex than the nuances in the C++ language or RPG's free-format syntax. After all, what happens today if I create a procedure named CHAIN and use it in free-format RPG?

Language-Independent Character Conversion Routines

In North America, this isn't too big an issue, but if you are writing code for multiple languages, it is a real pain. Trying to convert lowercase to uppercase or uppercase to lowercase may seem simple, but it isn't. The language code CCSID needs to be taken into consideration. There is an API available that does this conversion, but then everyone needs to write to that API. Why not just have a couple of built-in functions that do it for us?

The built-in functions would be %ToUpper and %ToLower. %ToUpper() would accept a fixed-length character field, a varying-length character field, or a literal value and convert it to the proper uppercase character set. %ToLower would work similarly.

Overloaded Procedure Parameters

This is something from the C++ language that I really like. It gives you the ability to seamlessly use different procedures without worrying about creating unique names for each one. For example, if you create a procedure that needs to add quotes around a field, you can declare that field as either a fixed-length field or a varying-length field, but not both. Why not? Because you can only modify a procedure parameter's value if it is not CONST and not passed by VALUE. Not using these options, however, causes the procedure to not accept other data types or variations as parameters.

If overloading were available, you could write two different procedures--both with the name QUOTE--that handle different types of parameters. One would accept fixed-length character fields. The other would accept varying-length character fields. Based on the type of data and parameter list you specified when calling the Quote() procedure, the compiler would select the correct one to call. The programmer using the Quote() procedure, however, does not know or care which one was actually evoked by the compiler.

Recognition of // as Comments

This feature would extend the existing /FREE comment syntax to the rest of the language--meaning that if positions 6 and 7 were blank (no statement type and no * in column 7), then the compiler could continue to look for // symbols. If it detected them, it would treat the line as a comment. This would allow consistent embedding of comments throughout the language. For example, the following would be valid:

.....CSRn01..............OpCode(ex)Extended-factor2++++++++++++++++++++
0006 C                   Read      CustRec
          // Read all customers until end of file
0007 C                   Dow       NOT %EOF
          // Compute the new due date base on the end of month
0008 C                   Eval      EndMonth = GetEndOfMonth(DueDate)
          // Write out the payment register
0009 C                   Except    Payments
0010 C                   Read      CustRec
0011 C                   enddo
0012 C                   Eval      *INLR = *ON

I could go on (I know there are others), but I told myself I'd limit this article to 10.

Who knows if IBM is listening, but I'd really like to hear what you think about these ideas. Please use the feedback forums or the poll below to tell me.

It's sort of a habit with me: Every few years, I create a list of things I'd like to see added to RPG. I normally post it on my Web site or publish it in an email to IBM Canada. Lately, however, I've been thinking that there really aren't 10 things I'd like to see added to RPG IV--rather, these are things that I think need to be added to or changed in the language.

So I've created this hybrid list of a few new features and a few changes. When I consider new features, I don't consider what it is I'm working on this week and need (the issue of the moment), but rather the long-term impact the feature would have to the language. So while I would really love to have something like a built-in function that reads comma-separated values into RPG, in the long run, that's probably not going to do me too much good. After all, how many times will I need to write a routine to read CSV files versus how many times I'll need something like CGI features in an application?

So here they are in no particular order, the top 10 features I'd like to see added to or changed in RPG IV:

  1. Built-in FTP capability via a %FTP() built-in function
  2. Case-insensitive %SCAN built-in function (maybe %SCANI() would do it?)
  3. Elimination of SEU as the default editor from the operating system
  4. Find and Replace built-in function
  5. Consistent implementation of new features
  6. Integrated support for CGI-related features and functions
  7. Integration with embedded SQL
  8. Language-independent character conversion routines--%ToUpper() and %ToLower()
  9. Overloaded procedure parameters
  10. Recognition of // as comments on any line without a character in column 6

Let's look at each one of these in more detail.

Built-In Support for FTP

I would love to have a %FTP() built-in function as part of RPG. How many times have you needed to get a file from another system and had to write an FTP script and then call a CL program to run that FTP script? Why not just allow the RPG program to do the work? This would require a few new built-in functions, perhaps something like the following:

ftp-handle = %FTPOpen( IP-address or domain : UserID : Password )
%FTPGet( ftp-handle : remote-file : local-file : *REPLACE )
%FTPPut( ftp-handle : local-file : remote-file : *REPLACE )
%FTPDir( ftp-handle : returned-list-of-files-in-directory )
%FTPCmd( ftp-handle : ftp-cmd )
%FTPReply( ftp-handle : ftp-reply-code-text )
%FTPClose( ftp-handle )

The idea is that you would open an FTP connection using the %FTPOpen built-in function. The %FTPOpen function would return a handle to the FTP session. That handle would then be used on all subsequent FTP built-in functions. This would allow multiple FTP sessions to be opened and processed at the same time.

Most of the FTP built-in functions listed above are self-explanatory. For example, the %FTPGet() and %FTPPut() built-in functions would be used to receive and send files, respectively. The %FTPDir() built-in function would generate a list of file names in the current working directory and return that list to the second parameter. The %FTPCmd() built-in function would allow any FTP command to be run, such as CD, RCMD, etc. The %FTPReply() built-in function would retrieve the reply code and text associated with the previous FTP command. Obviously, %FTPClose would close the FTP connection.

Case-Insensitive Scan

It is a pain to deal with upper/lowercase and the issue of language character sets, such as CCSID codes. We need a simple, case-insensitive scan function. This should be identical to %SCAN in syntax, but it should scan without concern for upper/lowercase. I'm suggesting %SCANI be used so that it can be easily plugged into existing code where it is needed.

Elimination of SEU from the Operation System

This is getting to me more and more lately. As most of you know, I wrote my own RPG editor for Windows (CodeStudio) way back before IBM ported CODE/400 to Windows. I continue to use it to this day. But I'm not advocating using CodeStudio over CODE/400 or vice versa. IBM and I have been doing that for years, and it just hasn't worked; most people still use SEU.

What I am advocating, however, is that IBM stop enhancing SEU and, in fact, stop automatically installing it with OS/400, beginning with OS/400 Version 6. The only way to get RPG programmers to move to CODE/400, Eclipse, or CodeStudio is to make using SEU more difficult.

Why do I advocate this? SEU is severely holding back the RPG development community. SEU may be a good fallback editor for quick and dirty jobs, but that is only true if you are not used to using one of the new editors. For more information on this topic, see "The Midrange Manager" in this issue.

Find and Replace Function

Currently, there are two functions you can use to search for and replace character fields in RPG. The first is %SCAN, and the second is %REPLACE. Using %SCAN is fairly simple, but using %REPLACE is, at best, complex. What would be helpful is an integrated find/replace function that combines these two functions. Something like this:

%FINDREPLACE(  find-text : replace-text : text-to-search : options )

Here, find-text is the text to be located, replace-text is the text to replace the find-text, text-to-search is the text being searched, and options is one or more controls. For example, options could be omitted, and the function would do a simple find/replace. Or options could be replaced with any one of the following: *MATCHCASE to cause a case-sensitive find/replace action, *NOCASE to cause a case-insensitive find/replace action (the default), *WORD to cause the find/replace action to match whole words only (no partial words), or *WILDCARD to indicate that the find-text parameter contains generic or "wildcard" characters. In addition, there should be an option to replace either just the first occurrence of the find-text or all occurrences, e.g., *ALL (the default) or *FIRST.

Also the length of the find-text and the replace-text should not need to be the same. The data would be automatically shifted within the text-to-search. So, for example, the following would work the way you'd expect it to:

%FindReplace( 'Midrange Computing' : 'MC Press' : Articles : *ALL)

All occurrences of "Midrange Computing" would be replaced with the words "MC Press" in the field named Articles.

New Feature Consistency

This is something that pains me in each new release. Due to legacy implementations and to a lesser extent, insufficient planning, new features are finding their way into RPG without IBM's taking into consideration existing features or potential future enhancements. Consequently, we end up with inconsistent keyword syntax and redundant functionality. Probably the biggest oops in this area is the implementation of Definition specification keywords.

Definition specification keywords that utilize literals such as those that need a file name or data area name are now being enhanced to support the use of a field name to contain those values.

For example, the DTAARA(MYDTA) and DTAARA(*VAR : MYDTA) keywords use two completely different syntaxes. In the first (original) syntax, MYDTA is the actual name of the data area. Unfortunately, it does not allow a data area to be qualified to a library name, nor does it allow a field name to be specified that contains the name of the data area.

Then, in V5R2, IBM introduced a new syntax that allows a field name to contain a data area name. In order for the compiler to know that the field name is a field name, IBM had to create a new syntax. Consequently, we have an alternate syntax for the DTAARA keyword: DTAARA(*VAR : MYDTA). The *VAR value indicates that the value of the second parameter is a field name that contains the name of the data area you want to read.

If it had been up to me, I would have circumvented this legacy flaw by simply creating a new keyword, perhaps EXTOBJ (external object), and allowed only a variable name or a quoted name to be specified for the first parameter. The second parameter would, of course, contain the object type so that other objects could be read into RPG just as easily as a data area is. For example, why not support EXTOBJ( myobj : *USRSPC), where myobj is a field containing a qualified object name and *USRSPC is the object type? This would allow us to easily read the contents of a user space object as well as any other object that may fit this design model.

Another inconsistency that seems troublesome is the use of record format names for some operations and built-in functions and file names for others. Database record names have not become an industry standard, and multi-format files are taboo. So why not allow us to specify either record format names or file names, and why not allow a record format name to be the same as a file name? That way, I wouldn't end up with code that looks like this:

.....FFileName++IFEASFRlen+LKeylnKFDevice+.Functions++++++++++++++++++++++++++
     FCustMast  UF   E           K DISK    RENAME(CustMast : CustRecUSROPN

.....CSRn01..............OpCode(ex)Extended-factor2+++++++++++
     C                   if        NOT %Open(CustMast)
     C                   Open      CustMast
     C                   Chain     CustRec
     C                   if        %Found(CustMast)
     C                   Eval      BalDue = 0
     C                   Update    CustRec
     C                   endif
     C                   endif

Integrated Support for CGI Functionality

I know this kind of thing is not popular with the RPG developers at IBM Canada, but I think it is necessary and critical to the survival of the language. Most other languages have integrated support for CGI programming, or they have extensive runtime libraries that provide essentially the same thing. RPG has neither and yet is one of the best languages to use for CGI programming.

What is needed to support CGI is the ability to retrieve data from an HTML form on a field-by-field basis, the ability to encode (that is escape) a text string such as a URL or HTML that is being sent to a browser session, and the ability to un-escape those same strings when they are read into RPG. Going overboard, there could also be functions to simplify the writing of HTML to the browser. This would require built-in support for writing to the standard-output device, including automatic detection of special character sequences, such as .

Better Integration with SQL

Do I even need to explain myself here? What I am proposing is that the SQL statements or commands be integrated with the RPG language. That is, from an RPG programmer's perspective, using SQL statement syntax would be no different from using the CHAIN opcodes in the new free-format syntax. You would just start a new line--no "C" or anything else in column 6 and no ridiculous plus sign (+) in column 7--and then code the SQL statement. And if the compiler detected the FETCH statement, it would assume you wanted the SQL Fetch statement. Consider the difference between parsing the SQL FETCH statement vs. using a procedure named FETCH--nothing could be more complex than the nuances in the C++ language or RPG's free-format syntax. After all, what happens today if I create a procedure named CHAIN and use it in free-format RPG?

Language-Independent Character Conversion Routines

In North America, this isn't too big an issue, but if you are writing code for multiple languages, it is a real pain. Trying to convert lowercase to uppercase or uppercase to lowercase may seem simple, but it isn't. The language code CCSID needs to be taken into consideration. There is an API available that does this conversion, but then everyone needs to write to that API. Why not just have a couple of built-in functions that do it for us?

The built-in functions would be %ToUpper and %ToLower. %ToUpper() would accept a fixed-length character field, a varying-length character field, or a literal value and convert it to the proper uppercase character set. %ToLower would work similarly.

Overloaded Procedure Parameters

This is something from the C++ language that I really like. It gives you the ability to seamlessly use different procedures without worrying about creating unique names for each one. For example, if you create a procedure that needs to add quotes around a field, you can declare that field as either a fixed-length field or a varying-length field, but not both. Why not? Because you can only modify a procedure parameter's value if it is not CONST and not passed by VALUE. Not using these options, however, causes the procedure to not accept other data types or variations as parameters.

If overloading were available, you could write two different procedures--both with the name QUOTE--that handle different types of parameters. One would accept fixed-length character fields. The other would accept varying-length character fields. Based on the type of data and parameter list you specified when calling the Quote() procedure, the compiler would select the correct one to call. The programmer using the Quote() procedure, however, does not know or care which one was actually evoked by the compiler.

Recognition of // as Comments

This feature would extend the existing /FREE comment syntax to the rest of the language--meaning that if positions 6 and 7 were blank (no statement type and no * in column 7), then the compiler could continue to look for // symbols. If it detected them, it would treat the line as a comment. This would allow consistent embedding of comments throughout the language. For example, the following would be valid:

.....CSRn01..............OpCode(ex)Extended-factor2++++++++++++++++++++
0006 C                   Read      CustRec
          // Read all customers until end of file
0007 C                   Dow       NOT %EOF
          // Compute the new due date base on the end of month
0008 C                   Eval      EndMonth = GetEndOfMonth(DueDate)
          // Write out the payment register
0009 C                   Except    Payments
0010 C                   Read      CustRec
0011 C                   enddo
0012 C                   Eval      *INLR = *ON

I could go on (I know there are others), but I told myself I'd limit this article to 10.

Who knows if IBM is listening, but I'd really like to hear what you think about these ideas. Please use the feedback forums or the poll below to tell me.

BLOG COMMENTS POWERED BY DISQUS