Adventure in Modernization

But sometimes, to old codgers like me, it’s difficult to know just how far to go. In previous posts I have written about my vaguely negative feelings about freeform RPG, and I have written very clearly about how I feel about IBM’s unwillingness to implement the MOVE instruction in freeform RPG, pointing out how this can only hinder conversion of old code and diminish acceptance of the new RPG dialect.

Case in point, a program I was working on today. I was writing code to implement formatting of a six-digit account number based upon the rightmost 6 digits of an 11-digit number. It was based upon some old code (the usual situation where I work), but the old code was hideous. The old program consisted of about 15 lines of MOVE and MOVEL statements. I said, this has got to go.

So I contemplated the best way to do it. I could set up a data structure and put pieces of the account number into that, using EVALs or MOVEs,with dashes embedded as needed. But that didn’t seem quite elegant enough. I have been working harder to modernize my own code, so I finally broke it down to these two possibilities, as illustrated in this test program. The result I am aiming for is the number formatted as 01-234-5.


     H DFTACTGRP(*NO)   ACTGRP(*CALLER)
     D BACTNO          S             11  0 INZ(99999012345)
     D ACC6            S              8    INZ(*BLANKS)
     D NUM6            S              6  0 INZ(0)
     D ACCW            C                   '0  -   - '
     C/FREE
       EVALR ACC6 = %EDITW(%DEC(%SUBST(%EDITC(BACTNO:'X'):6:6):6:0):ACCW);
      /END-FREE
     C                   MOVE      BACTNO        NUM6
     C                   EVALR     ACC6 = %EDITW(NUM6:ACCW)
     C                   EVAL      *INLR= *ON

One way mixes the old and the new, with an old-fashioned MOVE to the smaller field, followed by a new-fangled %EDITW BIF using a predefined edit word. The other goes full-bore new age, with one grand set of embedded functions. To get the 11 digit number in string form so I can substring it, I use %EDITC with an X edit code, which does the conversion. Next, I %SUBST (substring) the last six characters. I then use %DEC to convert those six characters back to numeric. Finally, I apply the %EDITW function to format those six digits as desired. (I would be interested in finding out about a shorter way to do it.)

But I have a problem with it. In an earlier post, I pointed out that the ability to create long, complex functions in freeform is not necessarily a virtue. The mere fact that I felt the need to explain it here indicates that I am not comfortable with it. The code is short, but I do not feel that it is clear. On the other hand, while the the two-line version using MOVE is short and sweet, and uses a BIF, it would force me to get out of freeform to use the MOVE; stylistically, that also seems wanting.

Since the thrust of my thinking is in trying to modernize the code so future generations of converted C programmers won’t be freaked out by the C in column 6, I am leaning toward the one-line version. But I don’t like it. It’s ugly.

5 Responses to “Adventure in Modernization”

  1. Brian May Says:

    I’ll be happy to help on this one. First, instead of

    EVALR ACC6 = %EDITW(%DEC(%SUBST(%EDITC(BACTNO:’X'):6:6):6:0):ACCW);

    I suggest:

    D ACCW C ‘ 0 - - ‘

    EvalR = %EditW(BActNo:ACCW);

    Using the EvalR will truncate the leading 5 numbers anyway.

    Secondly, when you do encounter a nasty situation like your original nested BIF’s, wrap it in a subprocedure in a service program and no one will have to know exactly how it works. That’s the whole point behind “Modern” RPG.

  2. Buck Says:

    I’m not overly fond of the numeric conversion / editing trick myself. I’m with you - I think it’s a bit on the ugly side, and somewhat a stumbling block as I try to read it. I’m far more pleased with self-documenting code; code that’s so straight forward, it doesn’t require a complex comment to explain it.

    Programmers from other languages (like C) will find the data structure example fairly easy, although using QUALIFIED will help that even more. People from a pure RPG II environment might have an easier time with the explicit %subst()

    For the record, I am an RPG II programmer, System/3. I don’t have much of a problem with the newer stuff in general. MOVE almost always had some head scratcher. A simple mis-definition of either the source or target and something odd would occur. And that old code was loaded with MOVE and MOVELs. Variables were defined wherever and looking up the definition of the variables involved invariably meant having a printed copy of the compiler listing handy (cross reference at the bottom.)

    Of course, I’m talking about maintenance. Writing new code wasn’t nearly as stressful because one keeps all the variables straight. But walking into someone else’s code… I can’t tell you how many times I scratched out the variables on scrap paper as I tried to decipher MOVE-laden code.

    Kudos for doing this blog. There aren’t any other RPG programmers doing what you do, and I hope this spurs discussion about the peculiarities of our craft. My comments are not intended as a criticism; my opinion is only one among many, and I have learnt much by being exposed to others - like yours.

    H DFTACTGRP(*NO) ACTGRP(’QILE’)

    d ds
    d BACTNO 11 0
    d ACC6 6 overlay(bactno: 6)
    d ACC_co 2 overlay(bactno: 6)
    d ACC_maj 3 overlay(bactno: 8)
    d ACC_min 1 overlay(bactno: 11)

    d formatted S 8 INZ

    C/FREE
    eval bactno = 99999012345;

    // explicit movement of data elements
    eval formatted = %subst(acc6: 1: 2) +
    ‘-’ +
    %subst(acc6: 3: 3) +
    ‘-’ +
    %subst(acc6: 6: 1);
    dsply formatted;

    // implicit movement of data elements
    eval formatted = acc_co +
    ‘-’ +
    acc_maj +
    ‘-’ +
    acc_min;
    dsply formatted;

    /END-FREE
    C EVAL *INLR= *ON

  3. Curtis Barron Says:

    I appreciate your response, Brian. I not sure why I didn’t think of that.

    Perhaps I didn’t think of the %editw BIF as effectively making it a string issue. I’ve been a little gun-shy of the EVAL statement ever since I first attempted to multiply a number by another (using EVAL) to create a number that would overflow and truncate the high end digits (as with the famous “magic number” method of flipping dates), and got a runtime error.

    I was, of course, aware of the possibility of creating a subprocedure in a service program, but when it came to creating a subprocedure or an inline calculation, it really didn’t make any difference. In either case, the nested BIFs would be ugly - even if I was the only one that knew it.

    Again, thanks for reading and responding.

  4. Curtis Barron Says:

    I appreciate your response, Buck. Actually, using a data structure is the least obscure way of doing it. I may have been thinking that I didn’t want to rely upon a data structure to do the formatting, since that would force the maintenance programmer to leave his C calculations and look up to the D specs to find out what the data structure was all about.

    But then, he would have to go up there to see what the other fields looked like anyway, so why would that be a problem? One data structure. one calculation line, and we’re done.

    Thanks a lot.

  5. Buck Says:

    Brian’s comment about hiding complexity with a subprocedure reflects one of the major breakthroughs in my own personal development as a programmer. I tend to naturally think in terms of functions rather than in code, so the idea of taking a complicated bit of code and converting it to a function / subprocedure was one of those AHA! moments for me.

    Not everyone will see it that way, of course, but I thought I’d throw that out there :-)

Leave a Reply