hi David,
We are obliged to code all our exported subprocedures with 2 data
structures as parameters. One for input, the other for output. The
"parameters" are actually the DS subfields. This idea was a work
around to avoid changing modules when one needed to add a parameter.
And... how does this achieve that goal, exactly? Every time you add a
parameter to your DS, you have to recompile everything or you'll corrupt
memory!
I suppose you could include a "Bytes Provided" field at the start of
your DSes like the IBM APIs do, and have every single routine that
references those variables check the bytes provided to make sure the
field it wants has been included.
But how is that any better than checking %PARMS? Indeed, I'd say it's
pretty much EXACTLY the same thing -- except that you have to check by
field offset instead of parameter count.
However, in the DS scenario, how do you make a field in the middle of
the structure optional? You have no equivalent to *OMIT...
How do you do bidirectional parameters (a parm that has both input and
output). Since you have one input and one output structure, there's no
where to put one parameter that's both input and output. If you do
allow both input/output within one of the structures, then you have to
do it for all of the parameters in that structure, since the CONST can
only be added to the whole structure or none of it.
Here's a really big one: You can never pass literals or existing
variables to your procedures. You always have to copy everything to
data structure first.
Indeed, every time you want to call a procedure, you have to build a
complex DS. You have to be careful to set the length properly (RPG won't
do it for you, like the way it sets %PARMS for you...) And if you
forget to fill in a field, there's no compiler routine that'll catch
that error. (A prototype would, if you had separate parameters)
So I don't see any advantages to this method. Only disadvantages.
Disadvantages are:
a) No bidirectional parameter support without discarding encapsulation
entirely.
b) Total size of all parameters is limited to 64k at v5r4, or 16M at 6.1
c) calling routines is significantly more cumbersome and complex (you
may as well go back to the days of CALL/PARM!)
d) No real error checking from the compiler (back to the days of
CALL/PARM there, too!)
e) No automatic setting of the sizes, so to avoid memory corruption you
have to rely on every caller to be coded correctly. (Something that
can't be reliably detected during testing!)
f) No ability to omit data in the middle, other than using "special
values" which have to be manually set by the caller.
g) Every time you check for an optional parameter, you have to manually
calculate the start position of the optional subfields. An error in
this would also not be detected by the compiler, or by testing,
resulting in memory corruption.
h) You can't ever call your routines from SQL or other languages that
don't support structures.
And all for WHAT? So you can check your own length instead of %PARMS?
What does any of this gain you? Can you provide even a single thing
that this does better than separate parameters do?!?!
Today, we find ourselves having to add the keyword EXTPROC(*CL) to
the prototype. Would it be reasonable to assume that we would never
have to add a keyword to a parameter, at a later release?
EXTPROC(*CL) isn't set on a parameter, it's set on the whole prototype.
It only matters if you have 1-byte return values, and since you say
all of your output is through an output parameter, I don't see how it
applies to you at all.
As an Amazon Associate we earn from qualifying purchases.