• The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
Menu
  • The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
  • Eliminate The Legitimate Use Of GOTO

    May 30, 2012 Ted Holt

    Today I want to share with you some of the ugliest RPG code I’ve ever seen. It is to me the programming-language equivalent of Quasimodo, the hunchback of Notre Dame, and I am its progenitor. Then I will tell you why I wrote this code, and why, despite its ugliness, the code was correct. Last, I will tell you how to “prettify” it.

    The ugly code of which I speak is in a template source code member for file maintenance programs. It is similar in structure to this example:

         P MoveItem        b
         D                 pi
         D  inItemID                      6a   const
         D  inWhsID                       3a   const
         D  inFromLocID                   7a   const
         D  inToLocID                     7a   const
         D  inQty                         5p 0 const
         D  ouStatus                      8a
          *** locals
         D AllOK           c                   const(*zeros)
         D Invalid         c                   const('1')
         D Active          c                   const('A')
         D ItemRec         ds                  likerec(Item: *input)     inz
         D WhsLocRec       ds                  likerec(WhsLoc: *input)   inz
         D StockLocRec     ds                  qualified                 inz
         D   In                                likerec(StockLoc: *input)
         D   Out                               likerec(StockLoc: *output)
         D                                     overlay(In)
    
          /free
              ouStatus = AllOK;
              if inQty = *zero;
                 return;
              endif;
    
              // open files
              monitor;
                 open items;
                 open whslocs;
                 open stocklocs;
              on-error;
                 %subst(ouStatus: 2: 1) = Invalid;
          /end-free
         C                   goto      MoveItemExit
          /free
              endmon;
    
              // verify input parameters
              chain inItemID Item ItemRec;
              if not %found() or ItemRec.Status <> Active;
                 %subst(ouStatus: 3: 1) = Invalid;
          /end-free
         C                   goto      MoveItemExit
          /free
              endif;
    
              chain (inWhsID: inToLocID) WhsLoc WhsLocRec;
              if not %found() or WhsLocRec.Status <> Active;
                 %subst(ouStatus: 5: 1) = Invalid;
          /end-free
         C                   goto      MoveItemExit
          /free
              endif;
    
              // Move the stock
              chain (inWhsID: inFromLocID: inItemID) StockLoc StockLocRec.In;
              if %found() and StockLocRec.In.QtyOnHand >= inQty;
                 StockLocRec.Out.QtyOnHand -= inQty;
                 update StockLoc StockLocRec.Out;
              else;
                 %subst(ouStatus: 6: 1) = Invalid;
          /end-free
         C                   goto      MoveItemExit
          /free
              endif;
    
              chain (inWhsID: inToLocID: inItemID) StockLoc StockLocRec.In;
              if %found();
                 StockLocRec.Out.QtyOnHand += inQty;
                 update StockLoc StockLocRec.Out;
              else;
                 StockLocRec.Out.Status = Active;
                 StockLocRec.Out.ItemID = inItemID;
                 StockLocRec.Out.WhsID  = inWhsID;
                 StockLocRec.Out.WhsLocID = inToLocID;
                 StockLocRec.Out.QtyOnHand = inQty;
                 write StockLoc StockLocRec.Out;
              endif;
    
              commit;
    
              // cleanup
          /end-free
         C     MoveItemExit  tag
          /free
              rolbk;
              close items;
              close whslocs;
              close stocklocs;
    
          /end-free
         P                 e
    

    I’d say this qualifies as ugly code by anyone’s standards. The ugliest thing to me is the way it flip-flops between free format and fixed format. But then there’s that other thing: GOTO.

    The fact is, I needed to use GOTO, and here’s why. The routine, which started as a subroutine, but which I later converted to a subprocedure, begins with an initialization phase, continues with the main routine, and ends with a few lines of cleanup calculations. Think about that for a minute with me.

    The initialization phase of a routine is where you run one-time calcs that set up the routine to do whatever it does. Here you might validate the values of parameters, allocate memory, open one or more files, initialize variables, etc.

    The main routine (the “meat”) is where the routine fulfills its mission.

    The cleanup phase is where you close files, deallocate memory, load values into output-only parameters, roll back uncommitted database transactions, and such.

    Some routines don’t have a cleanup phase. If an error is discovered during the execution of such a routine, so that it makes no sense to continue execution of the routine, control simply returns to the caller. That is, a routine with no cleanup can have multiple exit points, which are handled with operations like RETURN and LEAVESR.

    But what do you do when something goes wrong in a routine that has a cleanup phase, as this one does? You GOTO.

    And there lies the problem. Whereas most programming languages include a GOTO command, free-format RPG does not. So one either briefly resorts to fixed-format calculations or one finds an alternative.

    The alternative I prefer, and which I have used with great success, is to use a status variable. Often this is an output-only parameter, but it can also be a local variable, depending on the situation.

         P MoveItem        b
         D                 pi
         D  inItemID                      6a   const
         D  inWhsID                       3a   const
         D  inFromLocID                   7a   const
         D  inToLocID                     7a   const
         D  inQty                         5p 0 const
         D  ouStatus                      8a
          *** locals
         D AllOK           c                   const(*zeros)
         D Invalid         c                   const('1')
         D Active          c                   const('A')
         D ItemRec         ds                  likerec(Item: *input)     inz
         D WhsLocRec       ds                  likerec(WhsLoc: *input)   inz
         D StockLocRec     ds                  qualified                 inz
         D   In                                likerec(StockLoc: *input)
         D   Out                               likerec(StockLoc: *output)
         D                                     overlay(In)
    
          /free
              ouStatus = AllOK;
              if inQty = *zero;
                 return;
              endif;
    
              // open files
              monitor;
                 open items;
                 open whslocs;
                 open stocklocs;
              on-error;
                 %subst(ouStatus: 2: 1) = Invalid;
              endmon;
    
              // verify input parameters
              if ouStatus = AllOK;
                 chain inItemID Item ItemRec;
                 if not %found() or ItemRec.Status <> Active;
                    %subst(ouStatus: 3: 1) = Invalid;
                 endif;
              endif;
    
              if ouStatus = AllOK;
                 chain (inWhsID: inToLocID) WhsLoc WhsLocRec;
                 if not %found() or WhsLocRec.Status <> Active;
                    %subst(ouStatus: 5: 1) = Invalid;
                 endif;
              endif;
    
              if ouStatus = AllOK;
                 // Move the stock
                 chain (inWhsID: inFromLocID: inItemID) StockLoc StockLocRec.In;
                 if %found() and StockLocRec.In.QtyOnHand >= inQty;
                    StockLocRec.Out.QtyOnHand -= inQty;
                    update StockLoc StockLocRec.Out;
                 else;
                    %subst(ouStatus: 6: 1) = Invalid;
                 endif;
              endif;
    
              if ouStatus = AllOK;
                 chain (inWhsID: inToLocID: inItemID) StockLoc StockLocRec.In;
                 if %found();
                    StockLocRec.Out.QtyOnHand += inQty;
                    update StockLoc StockLocRec.Out;
                 else;
                    StockLocRec.Out.Status = Active;
                    StockLocRec.Out.ItemID = inItemID;
                    StockLocRec.Out.WhsID  = inWhsID;
                    StockLocRec.Out.WhsLocID = inToLocID;
                    StockLocRec.Out.QtyOnHand = inQty;
                    write StockLoc StockLocRec.Out;
                 endif;
              endif;
    
              if ouStatus = AllOK;
                 commit;
              else;
                 rolbk;
              endif;
    
              // cleanup
              close items;
              close whslocs;
              close stocklocs;
    
          /end-free
         P                 e
    

    Notice that there are five identical tests of the status code. Once the status code indicates that an error has been found, all remaining tests will automatically fail, and control will eventually reach the cleanup calcs.

    This is not the only way to eliminate the GOTO, but it’s a clean way.



                         Post this story to del.icio.us
                   Post this story to Digg
        Post this story to Slashdot

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Tags:

    Sponsored by
    Maxava

    Maxava Webinar: Modern High Availability for IBM i: Beyond Legacy Replication

    If you are reassessing your current HA strategy, evaluating alternatives, or planning for the next phase of your IBM i platform, this session will help you understand why replication alone is no longer the benchmark for availability, and what modern high availability should deliver instead.

    Register Now

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Sponsored Links

    Four Hundred Monitor Calendar:  Latest info on national conferences, local events, & Webinars
    IntelliChief:  The leading provider of Paperless Process Management solutions for the IBM i
    New Generation Software:  $475 IBM i Query & BI SDK. Order your FREE trial by June 30.

    IT Jungle Store Top Book Picks

    BACK IN STOCK: Easy Steps to Internet Programming for System i: List Price, $49.95

    The iSeries Express Web Implementer's Guide: List Price, $49.95
    The iSeries Pocket Database Guide: List Price, $59
    The iSeries Pocket SQL Guide: List Price, $59
    The iSeries Pocket WebFacing Primer: List Price, $39
    Migrating to WebSphere Express for iSeries: List Price, $49
    Getting Started with WebSphere Express for iSeries: List Price, $49
    The All-Everything Operating System: List Price, $35
    The Best Joomla! Tutorial Ever!: List Price, $19.95

    Preparing To Install IBM’s RUNSQL Command Three Ways To Fix NetServer Access Problems

    Leave a Reply Cancel reply

Volume 12, Number 15 -- May 30, 2012
THIS ISSUE SPONSORED BY:

WorksRight Software
CNX
Tembo Application Generation

Table of Contents

  • Preparing To Install IBM’s RUNSQL Command
  • Eliminate The Legitimate Use Of GOTO
  • Three Ways To Fix NetServer Access Problems

Content archive

  • The Four Hundred
  • Four Hundred Stuff
  • Four Hundred Guru

Recent Posts

  • No Joke: Big Memory And Flash Price Hikes Coming April 1
  • Strategic Topics To Think About For 2026, Part 2
  • Guru: IBM i Job Log Detective Brings Structure To Job Log Analysis In VS Code
  • IBM Launches Hybrid Cloud Backup Product With Cobalt Iron
  • IBM i PTF Guide, Volume 28, Number 10
  • Why You Need To Think About Offsite Data Protection
  • IBM Gets Bob 1.0 Off The Ground
  • You Store The Crown Jewels In A Safe, Not In A Bucket
  • More Power Systems Withdrawals, And Some From Red Hat, Too
  • Price Increases Are Here, Or Pending, And For Sure For Memory

Subscribe

To get news from IT Jungle sent to your inbox every week, subscribe to our newsletter.

Pages

  • About Us
  • Contact
  • Contributors
  • Four Hundred Monitor
  • IBM i PTF Guide
  • Media Kit
  • Subscribe

Search

Copyright © 2025 IT Jungle