On 27-Jan-2014 05:29 -0800, Briggs, Trevor (TBriggs2) wrote:
Barbara Morris on Friday, January 24, 2014 7:31 PM wrote:

On 1/24/2014 8:29 AM, Alan Cassidy wrote:

I just did this:
SNDPGMMSG MSG( 'Did not receive 3 parameters') TOPGMQ(*EXT)

Worked at least.

I just want to make sure that it's clear that this technique
should absolutely never be used.

It often seems to work in testing, but it's almost guaranteed to
give a false positive at some point, indicating that a parameter
was passed when it wasn't.

What's especially bad about this technique is that if your program
modifies a parameter that was not actually passed, you can cause

and unpredictable errors that might show up long after your program
has returned.

I have used a similar function in the past (using the "optional"
parameter name in the CHGVAR FROM rather than the TO variable), and
I was unaware of the fact that false positives could occur. I suppose
if there were a limited number of acceptable values for the parameter
that you could check against then the chances of "accidentally"
finding ones of these in a "phantom" parameter would be negligible.
But in cases where the parameter values could be a large number of
values it seems from this thread that IBM gives us NO 100% reliable
way of determining the number of parameters passed to a CL program.
Is that so?

To be sure, the topic is CLLE, not a CLP. An OPM CLP has an exact number of required parameters, so /optional/ is not even applicable; i.e. a CALL to a CLP with an incorrect number of arguments effects a CPD0172 "Parameters passed on CALL do not match those required." followed by a CPF0001 exception. The term "CL program" is probably still most often inferred as OPM *PGM with attribute CLP, not as a bound ILE CL *PGM with attribute CLLE [or perhaps "CLLE program"]... so I thought it worth mentioning.

As I had suggested a couple times in the thread, exactly what is the scenario needs to be fully defined, to know if the so-called optional parameter might in fact be [treated as] effectively being omissible; e.g. as when invoked as a Command Processing Program (CPP) for a Command Definition object (*CMD). The OP was never further clarified to include explicit information about the invokers nor the invoked, nor even the parameters and values, such that a reviewer might be able to make worthwhile suggestions about how to eliminate dependence on an /optional/ parameter.

A parameter for which the corresponding argument was _omitted_ by the invoker can safely be tested for *NULL, just as shown, forcing the exception. However /omitted/ is not the equivalent of /optional/.

Irrespective of how clearly implied [or not] in the docs, perhaps the technique remains valid for a CLLE compiled as a *PGM with CRTBNDCL for an invoker by CALL. I am unsure, but the call storage not being re-initialized between invocations, may apply only to procedure calls, not to program calls; that lack of initialization, being one of the factors improving the performance of procedure calls over program calls.? See for example <http://archive.midrange.com/rpg400-l/200806/msg00344.html> And FWiW I have never been able in tests, to produce a false-positive for an unspecified argument on a parameter of a CLLE program, as invoked by a CL CALL or RPGLE CALLP with fewer arguments; that is far from being proof. Regardless, a safe choice would be to assume the worst, and code even program calls, as if there were no support for optional parameters, just as must be done for procedure calls...

However I do know that a CLLE called as a procedure [i.e. a CLLE procedure], such as via the Call Bound Procedure (CALLPRC) or an equivalent, absolutely should never attempt to use that method of testing for *NULL to infer whether an argument was optionally passed [*NOPASS]. Specifically because that lack of re-initialization can lead to unpredictable results. And false-positives for a parameter apparently having a corresponding argument, regardless no argument had been specified by the invoker, is very easy to reproduce. So... That technique of testing for *NULL in a CLLE procedure is only valid for an argument that was omitted [*OMIT] by the invoker; or otherwise, if the language offers and the program is coded to use a separate capability that enables passing a null pointer as the address of the by-reference parameter.

Back to the specific case of a CPP for a *CMD object... Testing for *NULL is valid because every parameter keyword [defined by PARM() in the CMD source] will have an argument passed to the CPP. Any parameter keywords that are left unspecified with a variable name provided [per a RTNVAL(*YES) specification in the source] also will always get passed to the CPP by the command analyzer, but the address of the pointer to that parameter is *NULL; i.e. the same effect as for *OMIT parameter processing. Of course that also means that a prettier means of implementation, instead of testing for the *NULL by forcing the MCH3601 exception, is to directly test the address of the parameter against a Null Pointer; available since v5r4 with pointer support in CL.

This thread ...


Follow On AppleNews
Return to Archive home page | Return to MIDRANGE.COM home page

This mailing list archive is Copyright 1997-2020 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].