|
However, as far as I can tell actual implementation is ugly beyond belief.
One trick comes to mind... an *OMIT parameter is the same thing as a parameter who's address is *NULL. (In fact, the way you check for an *OMIT parameter is by checking if %addr() = *NULL)
Consequently, you could do this: D wToBin s 10A based(p_wToBin) D memToBin s like(wToBin) /free if bin_Required(); p_wToBin = %addr(memToBin); wToBin = AskUserForBin(); else; p_wToBin = *NULL; endif; Inventory_MoveSerialized(wPlant:wSerial:wToStkRm:wToBin); /end-freeWhen the bin isn't required, the address of wToBin is set to *NULL. That means it'll look like *OMIT to the procedure you call. This saves you from having to code the subprocedure call in two places.
/free if %parms >= 5; if parm5 <> *OMIT; SomeOtherProc1(plant:parm5); else; SomeOtherProc1(plant:*OMIT); endif; else SomeOtherProc1(plant); endif;
For stuff like this, I usually figure out my parameters at the beginning. For example:
if %parms >= 4 and %addr(Parm4)<> *NULL; local4 = Parm4; else; local4 = 'Default Value'; endif; if %parms >= 5 and %addr(Parm5) <> *NULL; Local5 = Parm5; else; Local5 = 'Default Value'; endif;This example is specifically for input-only parameters (i.e. CONST parms!) Because there's a local variable that's set, the procedure can simply use the local variable, and it doesn't have to have two sets of code for each thing that it does.
Naturally, it won't work for bi-directional or output parameters, since the Local5 variable isn't ever passed back. So for bi-directional or output parameters, you can do it this way:
D Local5 s like(Parm5) D based(p_Local5) D memLocal5 s like(Parm5) if %parms >= 5 and %addr(Parm5) <> *NULL; p_Local5 = %addr(Parm5); else; p_Local5 = %addr(memLocal5); endif;If the parm is passed, changes made to Local5 would change the parameter and be returned to the caller. If not, it'll change some local storage, which doesn't hurt anything.
If you need to be able to pass it on to the next procedure, you can pass Local5 to that procedure, and the next procedure will get your local storage or the caller's storage, again, depending on whether the parm was passed.
If the procedure that you call needs to know whether the original caller actually passed it or not, you can have a second based variable that's a "to be passed on" copy. For example
D Local5 s like(Parm5) D based(p_Local5) D PassMe5 s like(Parm5) D based(p_PassMe5) D memLocal5 s like(Parm5) if %parms >= 5 and %addr(Parm5) <> *NULL; p_Local5 = %addr(Parm5); p_Passme5 = %addr(Parm5); else; p_Local5 = %addr(memLocal5); p_Passme5 = *NULL; endif;Now when you need to pass it on, you pass "Passme5" and it'll automatically be set to *OMIT if the parameter wasn't passed. If it was passed, it'll be viewing the same memory that Local5 and the caller's parm were viewing, so the caller will know whether a parameter was passed or not, and can act differently if it needs to.
It's still somewhat ugly, but I think it's somewhat easier to maintain than the method you posted. If nothing else, it's food for thought.
As an Amazon Associate we earn from qualifying purchases.
This mailing list archive is Copyright 1997-2025 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].
Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.