IBM i > DEVELOPER > RPG

Dumping Subroutines: Breaking Up Is Hard To Do, Or Is It?


An Example

So, let’s get started with something easy and build on it. Here we have an older subroutine called $PRCDE. I’m from Wisconsin, which means it’s highly likely I work in one of three industries: motorcycles, beer or cheese. While I do own a Harley and have been known to enjoy an ice-cold beer, my livelihood comes from acidified milk mixed with the enzyme rennet and pressed into 640-pound blocks of pure goodness. At MGF, our cheese graders inspect and perform various tests on incoming vats of cheese to make sure it’s the best in quality and consistency every time. When they’re finished grading, they go into one of our applications and document what they found (or didn’t find). Sometimes a block of cheese can be loose knit, or curdy, meaning when the cheese was made the springs on the press that help mold the cheese could be worn or out of adjustment. This kind of cheese would be bad for bars, but perfectly fine for shreds, so it’s important to know if one of these defects exists. $PRCDE is the subroutine that writes these grading defects to a table in our database we will call VatNotes.

Here is the pure, untarnished $PrcCde subroutine before I got my hands on it. Notice it’s got that retro RPG III feel to it.

      //--------------------------------------------------------
      // Writes and updates to vat grading notes table
      //--------------------------------------------------------
     C     $PrcCde       Begsr  
      *
     C                   If        #sSel <> ' '
     C                   Eval      VGVCLC = ' '
     C                   Eval      vgdgre = ' '
     C                   Eval      VGLOT# =  #GLOT#
     C                   Eval      VGVAT# =  #GVAT#
     C                   Eval      #DVATD =  %dec(%char(%date(#GVDTE:*mdy)
     c                                       :*iso0):8:0)
     C                   Eval      VGVATC =  #GVATC
     C                   Eval      VGVATD =  #GVATD
     C                   Eval      VGVATM =  #GVATM
     C                   Eval      VGVATY =  #GVATY
     C                   Eval      VGCODE =  #sSel
     C                   Eval      VGUSM  =  ' '
     C                   Eval      VGDTM  =  0
     C                   Eval      VGTMM  =  0
     C     #KVGN01A      Chain     VatNotesRec
     C                   If        Not %Found(VatNotes02)
     C                   If        #sSel02 <> *blanks 
     C                   Eval      VGVCLC =  'C'
     C                   Eval      VGCDSC =  msdesc
     C                   Eval      VGUSC  =  #duser
     C                   Eval      VGDTC  =  %dec(%char(%Date():*iso0):8:0)
     C                   Eval      VGTMC  =  %dec(%char(%Time():*hms0):6:0)
     C                   Write     VatNotesRec
     C                   EndIf
     C                   else
     C                   Eval      VGCDSC =  #GCDSC
     C                   Eval      VGUSM  =  #duser
     C                   Eval      VGDTM  =  %dec(%char(%Date():*iso0):8:0)
     C                   Eval      VGTMM  =  %dec(%char(%Time():*hms0):6:0)
     c                   update    VatNotesRec
     C                   EndIf
     C                   Endif
     C                   Clear                   #ssel02
     C                   Endsr

     C                   exsr      $PrcCde      
     C                   Endsr
 

The problem with this is that even though a subroutine can be called multiple times, it isn’t flexible enough to be called from different areas of the application. #ssel02 is a display field that represents a grading code, and my job was to expand the program to write production codes to the table as well. Production codes represent production issues with cheese; for example, a code 29 could represent crumbly cheese. For me to write that code to file would mean either duplicating $PrcCde, or setting up #sSel02 and msdesc before calling the subroutine, hoping I didn’t mess up some other area of the program. The bigger a program gets the more difficult and time consuming it is to maintain, so for me both options are bad. There is a solution. It’s the RPGLE local subprocedure, and it’s easier than you think.

First, we’ll create a prototype in the program’s header (the D specs). Nothing fancy, just a one liner:

     D $PrcCde        PR   

Next, we modify the subroutine and make it into a procedure.

      //--------------------------------------------------------
      //  Procedure - $PrcCde       Process Code
      //--------------------------------------------------------
     P $PrcCde         B
      *
     C                   If        #sSel <> ' '
     C                   Eval      VGVCLC = ' '
     C                   Eval      vgdgre = ' '
     C                   Eval      VGLOT# =  #GLOT#
     C                   Eval      VGVAT# =  #GVAT#
     C                   Eval      #DVATD =  %dec(%char(%date(#GVDTE:*mdy)
     c                                       :*iso0):8:0)
     C                   Eval      VGVATC =  #GVATC
     C                   Eval      VGVATD =  #GVATD
     C                   Eval      VGVATM =  #GVATM
     C                   Eval      VGVATY =  #GVATY
     C                   Eval      VGCODE =  #sSel
     C                   Eval      VGUSM  =  ' '
     C                   Eval      VGDTM  =  0
     C                   Eval      VGTMM  =  0
     C     #KVGN01A      Chain     VatNotesRec
     C                   If        Not %Found(VatNotes02)
     C                   If        #sSel02 <> *blanks 
     C                   Eval      VGVCLC =  'C'
     C                   Eval      VGCDSC =  msdesc
     C                   Eval      VGUSC  =  #duser
     C                   Eval      VGDTC  =  %dec(%char(%Date():*iso0):8:0)
     C                   Eval      VGTMC  =  %dec(%char(%Time():*hms0):6:0)
     C                   Write     VatNotesRec
     C                   EndIf
     C                   else
     C                   Eval      VGCDSC =  #GCDSC
     C                   Eval      VGUSM  =  #duser
     C                   Eval      VGDTM  =  %dec(%char(%Date():*iso0):8:0)
     C                   Eval      VGTMM  =  %dec(%char(%Time():*hms0):6:0)
     c                   update    VatNotesRec
     C                   EndIf
     C                   Endif
     C                   Clear                   #ssel02
      *
     P                 E

Last but not least, we’ll modify our call. Instead of:

     C                   exsr      $PrcCde      

or the /free equivalent:

     Exsr  $PrcCde;  

Now we’ll use:

     C                   Callp      $PrcCde()    

Or, in /free, just:

     $PrcCde(); 

The subprocedure must be placed after all other specifications including output specs but before compile time arrays.

As you can see, not much has changed. In its current state, the procedure functions exactly the same as a subroutine. But now that our subprocedure works, we can expand to allow incoming parameters.

Production defects come from a different display field than grading defects. As such, we can add different arguments to our call to allow different outcomes. We change our prototype from:

     D $PrcCde         PR   

To:

     D $PrcCde         PR   
     D  code                      3     Value
     D  description              30     Value

It’s not required to name parameters in the prototype; however, it’s a good opportunity to describe what’s being passed to the procedure. I usually expand on the variables description. If the second argument passed is msdesc, I’ll put description in the prototype.

Brian Lannoye is a programmer at Masters Gallery Foods Inc., in Plymouth, Wis. He’s been working there as a programmer on the IBM i platform since June 2010. Brian regularly attends WMCPA meetings and is currently working toward a bachelor’s degree at Lakeland College Online.


comments powered by Disqus

Advertisement

Advertisement

2019 Solutions Edition

A Comprehensive Online Buyer's Guide to Solutions, Services and Education.

New and Improved XML-INTO

Namespace support makes the opcode a viable option

Authenticating on the Web

The finer points of OpenRPGUI, Part 1

The Microphone is Open

Add your voice: Should IBM i include open-source RPG tools?

IBM Systems Magazine Subscribe Box Read Now Link Subscribe Now Link iPad App Google Play Store
IBMi News Sign Up Today! Past News Letters