What Is the Difference Between *OMIT and *NOPASS? PDF Print E-mail
Programming - RPG
Written by Thomas Snyder   
Wednesday, 15 December 2010 00:00

Support MC Press - Visit Our Sponsors

Forums Sponsor

POPULAR FORUMS

Forums

Search Sponsor

Search

Do you know the best way to use optional parameters with procedures?

 

When you're using procedures, you have to ability to support optional parameters by using the special keywords *NOPASS and *OMIT. This article discusses the difference between the two and the appropriate times to use them.

*NOPASS

Let's begin with the *NOPASS option. The *NOPASS keyword specifies that the parameter is an optional parameter and does not need to be passed.

 

When you specify a parameter as being optional with the *NOPASS keyword, any subsequent parameters must also be specified as *NOPASS. This makes sense because, if you were allowed to skip parameters, how would the procedure being called be able to figure out which parameters you intend to send?

Determining How Many Parameters Were Passed

Once you specify parameters as being optional, you need to be able to support them within your procedure. Because the variables are not initialized, if you try to access them within the procedure, your program will crash or it will throw an exception if you are monitoring for it. To see how many parameters were passed, you can use the %parms built-in function (BIF) inside of your procedure. The %parms BIF will return the number of parameters that were passed into the procedure.

Creating a Procedure to Use *NOPASS

To illustrate the use of the *NOPASS special keyword, let's create a procedure that uses this functionality. For our example, we will create a procedure that uses the CPYTOIMPF command to export files to the IFS. This will allow us to easily export physical files with a simple line of code in our RPG programs.

 

For our programs, we will use the QCMDEXC API to execute our command. Here's the prototype for that:

 

     D* Prototype for QCMDEXC API

     D ExecuteCommand...

     D                 PR                  extPgm('QCMDEXC')

     D  argInCommand              65535A   const options(*varsize)

     D  argInLength                  15P 5 const

 

To illustrate the use of the *NOPASS keyword, we will create a procedure that calls the CPYTOIMPF command called exportFile. Here's the prototype for that:

 

     D* Prototype for CPYIMPF procedure

     D exportFile...

     D                 PR             1N

     D   argFromFile                 10A   const

     D   argFromLib                  10A   const options(*NOPASS)

     D   argFromMbr                  10A   const options(*NOPASS)

     D   argToFile                  512A   const options(*NOPASS)

 

The first parameter is the physical file that we are exporting from. Because we are exporting a file, this parameter is required, so I did not use the *NOPASS option on this one. But all the rest can be defaulted to another value, so these have been assigned to be optional using the *NOPASS keyword.

 

And here is our exportFile procedure using the *NOPASS keyword on three of the four parameters:

 

     P exportFile...

     P                 B                   EXPORT

     D exportFile...

     D                 PI             1N

     D   argFromFile                 10A   const

     D   argFromLib                  10A   const options(*NOPASS)

     D   argFromMbr                  10A   const options(*NOPASS)

     D   argToFile                  512A   const options(*NOPASS)

     D* Local Variables

     D   svReturn      S              1N

     D   svToFile      S            512A

     D   svCmdString   S           2000A

      /free

        svReturn = *OFF;

        //---------------------------------------------------------

        // Initialize the Defaults.

        //---------------------------------------------------------

        svToFile = %trim(argFromFile) + '.txt';

        if %parms > 3;

          svToFile = %trim(argToFile);

        endif;

        //-------------------------------------------------------------

        // CPYTOIMPF

        //-------------------------------------------------------------

        svCmdString = 'CPYTOIMPF FROMFILE(';

        // Library (Optional)

        if %parms > 1;

          svCmdString = %trim(svCmdString) + %trim(argFromLib) + '/';

        endif;

        // File (Mandatory)

        svCmdString = %trim(svCmdString) + %trim(argFromFile);

        // Member (Optional)

        if %parms > 2;

          svCmdString = %trim(svCmdString) + ' ' + %trim(argFromMbr);

        endif;

        svCmdString = %trim(svCmdString) + ') '

               + 'TOSTMF(''' + %trim(svToFile) + ''') MBROPT(*REPLACE) '

               + 'STMFCCSID(*PCASCII) RCDDLM(*CRLF) DTAFMT(*FIXED)';

        monitor;

          ExecuteCommand(%trim(svCmdString):%len(%trim(svCmdString)));

        on-error;

          // Exception

          svReturn = *ON;

        endmon;

        return svReturn;

      /end-free

     P                 E

 

For the library and the physical file member, we have dynamically built the CPYTOIMPF command to include them into the command to be executed if they were passed into the procedure. The target stream file to be created on the IFS will be defaulted to match the name of the physical file with a .txt extension if one was not specified.

 

To test out our procedure, we'll try a different permutation of each option available from the main procedure:

 

      /free

       if (exportFile('EMPHIST'));

         dsply 'Error on Export!';

       endif;

       if (exportFile('EMPHIST':'MYLIB'));

         dsply 'Error on Export!';

       endif;

       if (exportFile('EMPHIST':'MYLIB':'EMPHIST'));

         dsply 'Error on Export!';

       endif;

       if (exportFile('EMPHIST':'MYLIB':'EMPHIST':

                      '/Public/EmployeeHistory.txt'));

         dsply 'Error on Export!';

       endif;

       *inlr = *ON;

      /end-free

 

For our code sample, we allow the library and the member to be optional parameters and we set default values if they are not passed.

 

What if we want to use the default for the library but want to pass the member? Or what if we want to use the defaults for the library and member but specify the output file name? This is where the *OMIT keyword comes into play.

*OMIT

The *OMIT keyword indicates that the parameter is optional, but it will use the *OMIT special value as a placeholder to indicate that it is not being passed. Then we could have additional parameters after the omitted parameter. And with *OMIT, we do not have to specify the rest of the parameters as being omitted. This is because the optional parameter is being identified.

 

The *OMIT does identify the parameter as being valid, so you can't use the %parms keyword to determine if a parameter was omitted or not. And even if you could, if you had multiple omitted parameters, you wouldn't be able to determine which one was omitted—unless all of them were. So we could use the %ADDR to identify whether the parameter was omitted because the address will be null if it was omitted.

 

Here is our new version of the prototype that uses both *NOPASS and *OMIT:

 

     D* Prototype for CPYIMPF procedure

     D exportFile...

     D                 PR             1N

     D   argFromFile                 10A   const

     D   argFromLib                  10A   const

     D                                     options(*NOPASS: *OMIT)

     D   argFromMbr                  10A   const

     D                                     options(*NOPASS: *OMIT)

     D   argToFile                  512A   const

     D                                     options(*NOPASS: *OMIT)

 

And here is our new exportFile procedure using the *OMIT keyword:

 

     P exportFile...

     P                 B                   EXPORT

     D exportFile...

     D                 PI             1N

     D   argFromFile                 10A   const

     D   argFromLib                  10A   const

     D                                     options(*NOPASS: *OMIT)

     D   argFromMbr                  10A   const

     D                                     options(*NOPASS: *OMIT)

     D   argToFile                  512A   const

     D                                     options(*NOPASS: *OMIT)

     D* Local Variables

     D   svReturn      S              1N

     D   svToFile      S            512A

     D   svCmdString   S           2000A

      /free

        svReturn = *OFF;

        //---------------------------------------------------------

        // Initialize the Defaults.

        //---------------------------------------------------------

        svToFile = %trim(argFromFile) + '.txt';

        if %parms > 3;

          if %addr(argToFile) <> *NULL;

            svToFile = %trim(argToFile);

          endif;

        endif;

        //-------------------------------------------------------------

        // CPYTOIMPF

        //-------------------------------------------------------------

        svCmdString = 'CPYTOIMPF FROMFILE(';

        // Library (Optional)

        if %parms > 1;

          if %addr(argFromLib) <> *NULL;

            svCmdString = %trim(svCmdString) + %trim(argFromLib) + '/';

          endif;

        endif;

        // File (Mandatory)

        svCmdString = %trim(svCmdString) + %trim(argFromFile);

        // Member (Optional)

        if %parms > 2;

          if %addr(argFromMbr) <> *NULL;

            svCmdString = %trim(svCmdString) + ' ' + %trim(argFromMbr);

          endif;

        endif;

        svCmdString = %trim(svCmdString) + ') '

               + 'TOSTMF(''' + %trim(svToFile) + ''') MBROPT(*REPLACE) '

               + 'STMFCCSID(*PCASCII) RCDDLM(*CRLF) DTAFMT(*FIXED)';

        monitor;

          ExecuteCommand(%trim(svCmdString):%len(%trim(svCmdString)));

        on-error;

          // Exception

          svReturn = *ON;

        endmon;

        return svReturn;

      /end-free

     P                 E

 

It's not necessary to use *NOPASS with *OMIT. We could just specify *OMIT, which would require us to always pass the parameter and specify the *OMIT keyword if we want it to be omitted. I use a combination of both here for the most flexibility.

 

The main procedure will test out the modified exportFile procedure with the *OMIT keyword specified on the arguments. All of the tests in the previous main procedure will work because we still have *NOPASS specified, but now we can select which parameters will be passed and which ones will not.

 

      /free

       // Specify: File and Output File Name

       if (exportFile('EMPHIST':*OMIT:*OMIT:

                      '/Public/EmployeeHistory1.txt'));

         dsply 'Error on Export!';

       endif;

       // Specify: File, Library and Output File Name

       if (exportFile('EMPHIST':'MYLIB':*OMIT:

                      '/Public/EmployeeHistory2.txt'));

         dsply 'Error on Export!';

       endif;

       // Specify: File, Member and Output File Name

       if (exportFile('EMPHIST':*OMIT:'EMPHIST':

                      '/Public/EmployeeHistory3.txt'));

         dsply 'Error on Export!';

       endif;

       // Specify: Everything

       if (exportFile('EMPHIST':'MYLIB':'EMPHIST':

                      '/Public/EmployeeHistory4.txt'));

         dsply 'Error on Export!';

       endif;

       // Specify: Everything but Output File Name (Using *OMIT)

       if (exportFile('EMPHIST':'MYLIB':'MCPRESS':*OMIT));

         dsply 'Error on Export!';

       endif;

       // Specify: Everything but Output File Name (Using *NOPASS)

       if (exportFile('EMPHIST':*OMIT:'MCPRESS'));

         dsply 'Error on Export!';

       endif;

       *inlr = *ON;

      /end-free

 

On review of this main procedure, you can see that you could selectively pass whichever values you want to use to override the default values, or you could not pass them at all.

CPYTOIMPF (STMFCODPAG Changed to STMFCCSID)

Notice that I am using the STMFCCSID parameter with the CPYTOIMPF command because I'm using V6R1. The V5R4 box used STMFCODPAG, which is still supported but is not listed when you prompt the command and is intended to be removed in a later release.

 

If you use this procedure to perform your exports, you only need to change the syntax in one procedure, and all of your programs using this functionality will be updated.

Using *OMIT on the Last Parameter

You don't need to specify *OMIT on the last parameter; you don't really need a placeholder here because there is nothing after it. But, when I'm building reusable procedures that I intend to use in the future, I like to code them in such a way that I have to do minimal thinking when using them. So, if I were to assume I could use *OMIT for all optional parameters, then my procedure will support it because my procedure is programmed to handle it. That way, if I were to pass in *OMIT in the last parameter, it will not see it as a valid file name and will behave as expected. And who knows, you may add additional parameters later on.

The Output

If you view the output using Qshell, you can see the files that were created. You can enter Qshell by typing STRQSH on the command line.

 

121510Snyder_fig01

Figure 1: Use Qshell to see the files created on the IFS. (Click images to enlarge.)

 

For the files that were exported without a specified name, the default name was assigned to match the name of the physical file with a .txt extension. All the rest were placed into the Public folder, as specified within the program.

Download the Code

You can download the code used in this article by clicking here.

 

121510Snyder_fig02

as/400, os/400, iseries, system i, i5/os, ibm i, power systems, 6.1, 7.1, V7,


Thomas Snyder
About the Author:

Tom Snyder has a diverse spectrum of programming experience encompassing IBM technologies, open-source, Apple, and Microsoft and utilizing these technologies with applications on the server, on the web, or on mobile devices.

 

Tom has over 20 years experience as a software developer in various environments, primarily in RPG, Java, C#, and PHP and holds certifications in Java from Sun and PHP from Zend. Prior to software development, Tom worked as a Hardware Engineer at Intel and is a proud United States Naval Veteran Submariner who served aboard the USS Whale SSN638 submarine.

 

Tom is the best-selling author of Advanced Integrated RPG, which covers the latest programming techniques for RPG ILE and Java to utilize open-source technologies.

 

Originally from and currently residing in Scranton, Pennsylvania. Tom is currently involved in a Mobile Application Start-up company named JoltRabbit LLC.

 

 


MC Press books written by Thomas Snyder available now on the MC Press Bookstore.

 

Advanced, Integrated RPG Advanced, Integrated RPG

This book shows you how to take advantage of the latest technologies from within existing RPG applications.

List Price $79.95
Now On Sale
 

 

Read More >>
Last Updated on Tuesday, 14 December 2010 13:56
 
User Rating: / 4
PoorBest 
   MC-STORE.COM