• 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
    New Generation Software

    FREE Webinar:

    Creating Great Data for Enterprise AI

    Enterprise AI relies on many data sources and types, but every AI project needs a data quality, governance, and security plan.

    Wherever and however you want to analyze your data, adopting modern ETL and BI software like NGS-IQ is a great way to support your effort.

    Webinar: June 26, 2025

    RSVP today.

    www.ngsi.com – 800-824-1220

    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

    CA Product Manager Bill Hunt: 1964-2012 As I See It: Pocket Litter

    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

  • Public Preview For Watson Code Assistant for i Available Soon
  • COMMON Youth Movement Continues at POWERUp 2025
  • IBM Preserves Memory Investments Across Power10 And Power11
  • Eradani Uses AI For New EDI And API Service
  • Picking Apart IBM’s $150 Billion In US Manufacturing And R&D
  • FAX/400 And CICS For i Are Dead. What Will IBM Kill Next?
  • Fresche Overhauls X-Analysis With Web UI, AI Smarts
  • Is It Time To Add The Rust Programming Language To IBM i?
  • Is IBM Going To Raise Prices On Power10 Expert Care?
  • IBM i PTF Guide, Volume 27, Number 20

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