• The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
Menu
  • The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
  • How to Use the *NOPASS and *OMIT Parameter Options

    January 5, 2005 Hey, Joel

    I notice that you use *nopass extensively in your free xRPG procedures to offer flexibility in your procedure calls, but you don’t seem to use *omit. I recently came across an example of a prototype that used both for the same parameter. Can you explain the difference between the two, why you use one but not the other, and why someone would use them together like this?

    –Rob

    Let me start by explaining the two options and how they differ.

    *NOPASS

    The *nopass parameter option allows you to not pass the parameter at all. Consider the prototype for the getDateStrUSA procedure from my xRPG Core Library :

    d getDateStrUSA   pr            10    varying
    d  date                           d   const options( *nopass )
    d  zero                           n   const options( *nopass )
    d  inc                            n   const options( *nopass )
    d  sep                           1    const options( *nopass ) 
    

    You’ll notice right away that all the parameters use options(*nopass), meaning that they are completely optional. The first rule of *nopass is that every parameter after an optional one is also optional. This means that I have five different parameter lists for calling this procedure:

     /free
        // Get Todays Date as a USA Formatted Date String
        usaDateString = getDateStrUSA();   
    
        // Get This Date as a USA Formatted Date String
        usaDateString = getDateStrUSA( dateField );
    
        // Get This Date as a USA Formatted Date String,
        //  not zero-suppressed
        usaDateString = getDateStrUSA( dateField : *off );
    
        // Get This Date as a USA Formatted Date String,
        //  not zero-suppressed, with separators
        usaDateString = getDateStrUSA( dateField : *off : *on );
    
        // Get This Date as a USA Formatted Date String,
        //  not zero-suppressed, with separators, use "." as separator
        usaDateString = getDateStrUSA( dateField : *off : *on : '.' );
     /end-free
    

    You’ll notice the functionality changes with each parameter, again adding to the flexibility and usefulness of this procedure. This does require some coding discipline in the procedure. First of all, when you allow optional parameters, you must check inside the procedure to see whether the parameters were sent. This is done with the %parms() built-in function.

    You also must be aware that while a parameter in a procedure interface defines a local variable in the procedure, you must not use the parameter if it is not sent. The best way I’ve seen to handle this is to define variables within the procedure that match the incoming parameters and then use the parameter list to set their values. This also allows you to easily establish behavioral defaults for the procedure that are used in the absence of the sent parameters. Below is the code from my getDateStrUSA procedure that handles the parms coming in:

    d getDateStrUSA   pi            10    varying
    d  date                           d   const options( *nopass )
    d  zero                           n   const options( *nopass )
    d  inc                            n   const options( *nopass )
    d  sep                           1    const options( *nopass ) 
    
    d  dateIn         s               d
    d  zeroSuppress   s               n   inz( *on )
    d  incSeps        s               n   inz( *on )
    d  sepChar        s              1    inz( '/' )
    
     /free
       select ;
          when  %parms() = 0 ;
            dateIn = %date();
          when  %parms() = 1 ;
            dateIn = date ;
          when  %parms() = 2 ;
            dateIn = date ;
            zeroSuppress = zero ;
          when  %parms() = 3 ;
            dateIn = date ;
            zeroSuppress = zero ;
            incSeps = inc ;
          when  %parms() = 4 ;
            dateIn = date ;
            zeroSuppress = zero ;
            incSeps = inc ;
            sepChar = sep ;
        endsl ;
     /end-free
    

    Notice how I set the default values in the procedure’s D–specs. These values are then overwritten if the parameters were sent. Now the rest of the code uses the Standalone fields defined in the procedure and not the parameter variables defined in the Procedure Interface.

    *OMIT

    The *omit parameter option allows you to not send a value for a parameter, but, unlike *nopass, it does require you to send a placeholder. If you are not going to send a value, *null must be sent in the parameter location. Using the same example procedure from above, had I used *omit instead of *nopass, the prototype would look like so:

    d getDateStrUSA   pr            10    varying
    d  date                           d   const options( *omit )
    d  zero                           n   const options( *omit )
    d  inc                            n   const options( *omit )
    d  sep                           1    const options( *omit ) 
    

    Using *omit would also change the way I can call this procedure:

     /free
        // Get Todays Date as a USA Formatted Date String
        usaDateString = getDateStrUSA( *omit : *omit : *omit : *omit );   
    
        // Get This Date as a USA Formatted Date String
        usaDateString = getDateStrUSA( dateField : *omit : *omit : *omit );
    
        // Get This Date as a USA Formatted Date String,
        //  not zero-suppressed
        usaDateString = getDateStrUSA( dateField : *off : *omit : *omit );
    
        // Get This Date as a USA Formatted Date String,
        //  not zero-suppressed, with separators
        usaDateString = getDateStrUSA( dateField : *off : *on : *omit );
    
        // Get This Date as a USA Formatted Date String,
        //  not zero-suppressed, with separators, use "." as separator
        usaDateString = getDateStrUSA( dateField : *off : *on : '.' );
     /end-free
    

    I hope you agree that this is less elegant than *nopass. The good news is that, unlike *nopass, which requires every parameter after a nopass parameter to also be *nopass, you can pick and choose which parameters you want to be omittable.

    Handling the parameter checking in the procedure code is also different. Instead of checking for whether the parameter has been sent, you have to check whether a value or the *null placeholder was sent, by using the %addr() BIF.

    d getDateStrUSA   pi            10    varying
    d  date                           d   const options( *omit )
    d  zero                           n   const options( *omit )
    d  inc                            n   const options( *omit )
    d  sep                           1    const options( *omit ) 
    
    d  dateIn         s               d
    d  zeroSuppress   s               n   inz( *on )
    d  incSeps        s               n   inz( *on )
    d  sepChar        s              1    inz( '/' )
    
     /free
        if %addr( date ) = *NULL ;
          dateIn = %date();
        else ;
          dateIn = date ;
        endif ;
    
        if %addr( zero ) <> *NULL ;
          zeroSuppress = zero ;
        endif ;
    
        if %addr( inc ) <> *NULL ;
          incSeps = inc ;
        endif ;
    
        if %addr( sep ) <> *NULL ;
          sepChar = sep ;
        endif ;
     /end-free
    

    Again, I can rely on the default values in the procedure and only change them if the parameter was not omitted.

    Using Both Together

    One interesting approach is to combine *nopass and *omit:

    d getDateStrUSA   pr            10    varying
    d  date                           d   const options( *nopass : *omit )
    d  zero                           n   const options( *nopass : *omit )
    d  inc                            n   const options( *nopass : *omit )
    d  sep                           1    const options( *nopass : *omit ) 
    

    I now have an interesting assortment of calling parameter lists. I won’t list them all here, but I will answer the question I’m sure you are asking right now: why would anyone do this?

    Take the procedure I’ve been using as an example. The parameters have a series of defaults for the optional parameters. If the programmer wants to use option 4 to change the separator character to something other than the default, but wants the default behavior for parameters 1, 2, and 3, then he must know what values to pass to represent those defaults. Using this approach still allows the caller to have flexibility, without requiring the programmer to know what values to send to represent the default behavior. In this case, it could look like this instead:

     /free
        // Get This Date as a USA Formatted Date String,
        //  zero-suppressed, with separators, use "." as separator
        usaDateString = getDateStrUSA( *omit : *omit : *omit : '.' );
     /end-free
    

    Now the programmer doesn’t have to research to remember that he should send %date(), *on, *on for the first three parameters. This could also allow the developer to change the default procedure behaviors without the programmer needing to change the calling code. I’ll leave it to the reader to determine the pros and cons of that approach.

    Using both options also increases the work you must do in order to handle those incoming parameters. If sent, the *omit placeholder counts as a parameter, just one whose value is null. So basically you have to check for whether a parm was sent and whether it has a value of null:

    d getDateStrUSA   pi            10    varying
    d  date                           d   const options( *nopass : *omit )
    d  zero                           n   const options( *nopass : *omit )
    d  inc                            n   const options( *nopass : *omit )
    d  sep                           1    const options( *nopass : *omit ) 
    
    d  dateIn         s               d
    d  zeroSuppress   s               n   inz( *on )
    d  incSeps        s               n   inz( *on )
    d  sepChar        s              1    inz( '/' )
    
     /free
        if %parms() = 0 ;
          dateIn = %date();
        endif ;
    
        if %parms() > 0 ;
          if %addr( date ) = *NULL ;
            dateIn = %date();
          else ;
            dateIn = date ;
          endif ;
        endif ;
    
        if %parms()> 1 ;
          if %addr( zero ) <> *NULL ;
            zeroSuppress = zero ;
          endif ;
    
        if %parms()> 2 ;
          if %addr( inc ) <> *NULL ;
            incSeps = inc ;
          endif ;
        endif ;
    
        if %parms()> 3 ;
          if %addr( sep ) <> *NULL ;
            sepChar = sep ;
          endif ;
        endif ;
     /end-free
    


    It is true that I favor *nopass over *omit, almost to the point of exclusivity. Originally this was a conscious choice, because the logic of *omit didn’t make a lot of sense to me. I mean that if I have to send a parameter, why not send the correct value as well? However, as I develop more and more procedures for other programmers, I find that practical flexibility is of extreme value. For the cost of a little extra parameter checking, I can use both options together to add even more flexibility to a procedure. To me, that is something very worthwhile.

    –Joel Cochran

    Joel Cochran is the director of research and development for a small software firm in Staunton, Virginia, and is the author and publisher of www.RPGNext.com. Click here to contact Joel by e-mail.

    This article has been corrected since its original publication. In the last section of code, the “date” and “dateIn” variable names were presented in the wrong order. IT Jungle regrets the error. [Correction made 1/6/05]

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Tags:

    Sponsored by
    Maxava

    Migrate IBM i with Confidence

    Tired of costly and risky migrations? Maxava Migrate Live minimizes disruption with seamless transitions. Upgrading to Power10 or cloud hosted system, Maxava has you covered!

    Learn More

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Inovis Unveils Unified E-Business Product Line Tango/04 Delivers Affordable BSM, or ‘Tivoli for the Rest of Us’

    Leave a Reply Cancel reply

Volume 5, Number 1 -- January 5, 2005
THIS ISSUE
SPONSORED BY:

WorksRight Software
iTera
Guild Companies

Table of Contents

  • Get Organized with the WDSc Tasks View
  • How to Use the *NOPASS and *OMIT Parameter Options
  • Admin Alert: Preparing for an OS/400 V5R1 to V5R3 Upgrade

Content archive

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

Recent Posts

  • Meet The Next Gen Of IBMers Helping To Build IBM i
  • Looks Like IBM Is Building A Linux-Like PASE For IBM i After All
  • Will Independent IBM i Clouds Survive PowerVS?
  • Now, IBM Is Jacking Up Hardware Maintenance Prices
  • IBM i PTF Guide, Volume 27, Number 24
  • Big Blue Raises IBM i License Transfer Fees, Other Prices
  • Keep The IBM i Youth Movement Going With More Training, Better Tools
  • Remain Begins Migrating DevOps Tools To VS Code
  • IBM Readies LTO-10 Tape Drives And Libraries
  • IBM i PTF Guide, Volume 27, Number 23

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