Much like COBOL, RPG isn't going away any time soon, so let's see if we can get some new features!
Many of us in the industry have been working with RPG for 30 or more years. We can remember back to the time when the CALL opcode was added, which changed the language forever. Now, RPG is as full-featured a language as any out there and includes the still unparalleled direct access to the database that makes RPG programs run rings around any other programming environment. So what could improve it? Well, I can certainly think of a few things.
First Off, Bring Back FRED!
Actually, FRED is not quite the correct venue, but let me explain. FRED stands for Feature Request Database that existed some time ago for WDSC enhancements (back when there was such a thing as WDSC). It was a place where people could submit their requests for new or enhanced features, although to be precise it was for WDSC, not the RPG language itself. For RPG, IBM also would occasionally request enhancement suggestions from the community through a technique of giving people a budget and letting them spend their budget dollars on various enhancements based on prices set by IBM.
The only technique available today is the Design Change Request, or DCR, but as far as I know there's no way to review those DCRs and provide any feedback to IBM as to which is really needed. The DCR is the ultimate squeaky wheel: those who take the time to go through the process are the ones heard by IBM. Me, I'd like to see something more like some of the open-source development projects where enhancement requests are listed and people can vote for them. I've revamped the Pluta Brothers Design site, and there's a new section called Community where I'm going to start gathering requirements and maybe even putting out polls. I'll package up that information and send it off to whoever will listen at IBM.
What Would You Ask For?
OK, assuming that there was such a place to request new features, what exactly would I request? Let me go off in a few different directions here and see if it perhaps gets your brain percolating a little. I'll start with a couple of larger areas.
Procedure Overloading
I'm stealing a term that describes how Java implements the concept of polymorphism. With overloading, you can have the same procedure name with different parameter lists, and each parameter list would then call a different procedure. Among other things, overloading allows you to define procedures that accept different combinations of parameters without having to have a lot of *OMIT parameters. An example would be the following:
nextDay = AddDays( startDate: days);
I'd like to be able to pass in either a numeric value or a date parameter. Either way, I'd like the procedure to return that date plus (in this case) one day. The code might look something like this:
p AddDays b
d pi d
d numDate 8s 0
d days 5u 0
/free
return (AddDays( %date(numDate): days));
/end-free
p e
p AddDays b
d pi d
d isoDate d
d days 5u 0
/free
return ( isoDate + %days(days));
/end-free
p e
You'll note two different definitions for the AddDays procedure: one with an 8S0 numeric input parameter for the date, and one with a type D date field. Both would reside in the same service program. And while this is a simple example, a subtle but very important point is that the first version calls the second version. The first version simply converts the numeric date to a D date and sends that converted value to the second version. This is a very common pattern in OO programming because it allows you to put all the actual programming logic in one procedure. It doesn't matter much in this case, but imagine if this were a complicated business algorithm that used values from the database and so on. Rather than cloning the logic, you keep it all in one place. That way, when you do have to change the logic, you only need to change it in one place. Polymorphism helps encourage that practice.
Name Spaces for Service Programs
The idea would be that you could have the same procedure name in two different service programs and call one or the other by specifying the service program name as the prefix to the procedure. The reason is simple; it allows you to avoid collisions between two service programs. You may not think that service programs would collide, but they can do so quite easily. As a very simple example, let's assume that all your service programs use a common error infrastructure in which the called procedure signals an error via a return code but allows the caller to extract more detailed information on demand. Your code might look like this:
if GetTradingPartner( customer: partnerID) <> 0;
errorInfo = GetLastErrorInfo();
endif;
The name GetTradingPartner might be unique among your service programs, but if you use this architecture regularly, the name GetLastErrorInfo will not be. So unfortunately if you were to use two service programs in the same application, you would have a conflict between the two procedures. It would be nice if the compiler would allow you to identify the service program name in the program and use that as a disambiguating value during the ILE binding process, tying each procedure call to the corresponding service program:
if GetTradingPartner( customer: partnerID) <> 0;
errorInfo = XmlService.GetLastErrorInfo();
endif;
Of course, this means you'd have to have a way to tie the prefix (in this case, XmlService) to the appropriate service program, which would mean some tweaks to the ILE binding process. And the polymorphism above would also require an enhanced ILE binding process, but I can dream, can't I?
Well, those are my big areas. Let's move down to some smaller things that might make life a little easier.
Ternary BIF
I have to admit that when I first saw it, I absolutely hated the ternary operator. It seems clunky and arbitrary and unnecessary. But over the years I've really come to appreciate it, especially since in RPG it allows me to condense five lines of code into one. Here's what the code might look like:
shipDate = %cond-value(RequestedDate <> *loval : RequestedDate : OrderDate);
I call my version the %cond-value (conditional value) BIF. You pass in three values: a Boolean indicator followed by two values of the same type. If the Boolean is true, the BIF returns the first value; otherwise, it returns the second. Thus the line above replaces this code:
if RequestedDate <> *loval;
shipDate = RequestedDate;
else;
shipDate = OrderDate;
endif;
Simple, easy to understand. The compiler would have to do some work; the two values would have to be compatible, and both would have to be compatible with the target. But in essence, you'd just do the same tests that you'd have to do for the if/else/endif code. And removing four lines of code, two of which consist of nothing more than an opcode, is always a good idea in my book.
More Than One Line per Physical Line
Another way to reduce the number of lines in a source member is to make better use of them, and you could theoretically do that by allowing multiple operations on one source line:
if RequestedDate <> *loval; shipDate = RequestedDate; else; shipDate = OrderDate; endif;
Of course, if I did that, I'd go past the 80-character source line limit. Which brings up another minor enhancement.
Allow /free to Span the Entire Source Line
This ought to be self-explanatory.
Are There Others?
Well, yes, I've got quite a few others! And I'm sure you could come up with several of your own just by sitting and thinking over what you've coded the last few weeks. Why not share those ideas in the comments? Who knows, maybe we can get IBM to listen to us!
LATEST COMMENTS
MC Press Online