On 20/07/2008, at 2:41 AM, Mark S. Waterbury wrote:
I find that when using any preprocessor-type compiler directives,
in any
language, it is best to keep the conditions very simple. If it
requires
a more complex conditional test, with ANDs and ORs etc., I find it is
usually better to code that logic within the HLL language itself, e.g.
using real "if" statements, where the values to be tested are
initialized at compile-time and are never altered by the program,
and so
the compiler "back-end" recognizes this and will usually "optimize
out"
any unused branches (so-called "dead code" removal). This also makes
for much more readable source code, in my opinion.
I agree that there is less "magic" happening when the code does the
work. You only have to examine some of the C include structures to
see what a mess can be created when the pre-compiler is over-used.
In your particular example, you could declare "doStuff" as a procedure
pointer, and in an *INZSR, initialize it to the appropriate procedure
pointer e.g., using the QleActBndPgm API to dynamically load/activate
the needed *SRVPGM(s) and then calling the QleGetExp API to resolve to
any needed procedure(s) within that service program, assigning the
appropriate pointers (to "doStuff").
Then, the rest of the application just calls "doStuff" as usual,
and at
runtime it will point to the correct procedure.
Does this make sense?
Oh yes. I've used that approach in the past where I had complete
control over the application. It can result in very elegant code. In
one case I had code driven completely by a structure of function
identifiers and function pointers--very neat
In this instance I am simply providing an include which the consumer
controls by setting /DEFINE values. The underlying code for which the
include provides the definitions and prototypes is not mine nor can I
provide any wrapper code to choose which function is ultimately
called. Essentially, I'm trying to create RPG IV compatible
definitions for a C include which does use && and || logic in the pre-
compiler.
The simple solution would be to just let the consumer decide whether
to invoke function1, function2, or function3 but since they all have
an identical interface but different run-time behaviour I wanted to
allow the caller to write doStuff(x, y) and have the appropriate
function be called simply by recompiling. In this case there is no
need to flip between behaviours at run-time. The developer would
choose the appropriate behaviour and it would never need to change.
I'm doing something different but think of it like the LARGE_FILE
support in C. A C programmer simply codes, creat(), open(), stat(),
etc. and can then "magically" make the code handle large files (>
2GB) simply by defining _LARGE_FILES (or _LARGE_FILE_API or
specifying SYSIFCOPT(*IFS64IO)) they can now process large files with
no code changes.
That's the sort of behaviour I'm trying to emulate. That way the
consumer gets one set of "how to use" documentation that works for
COBOL, RPG, and C instead of special-case stuff for RPG IV.
Most published efforts at prototyping the IFS APIs simply code
prototypes for all the various functions and let the consumer decide
whether to call open() or open64(). I'd prefer that sort of choice to
be handled by /DEFINE statements.
Regards,
Simon Coulter.
--------------------------------------------------------------------
FlyByNight Software OS/400, i5/OS Technical Specialists
http://www.flybynight.com.au/
Phone: +61 2 6657 8251 Mobile: +61 0411 091 400 /"\
Fax: +61 2 6657 8251 \ /
X
ASCII Ribbon campaign against HTML E-Mail / \
--------------------------------------------------------------------
As an Amazon Associate we earn from qualifying purchases.