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:
CHGVAR &VALUE3 &PARAMETER3
MONMSG MCH3601 EXEC(DO)
SNDPGMMSG MSG( 'Did not receive 3 parameters') TOPGMQ(*EXT)
ENDDO
ENDPGM
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
bizarre
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.
As an Amazon Associate we earn from qualifying purchases.