× The internal search function is temporarily non-functional. The current search engine is no longer viable and we are researching alternatives.
As a stop gap measure, we are using Google's custom search engine service.
If you know of an easy to use, open source, search engine ... please contact support@midrange.com.



Duane,

Conventionally you need to have two solutions:

1) If a procedure is local to the module and is not EXPORTed then the
prototype is still required and can be "hard coded" in the global D spec
area of the source member. No "copybook" is required.

2) If a procedure is going to be used anywhere outside of the module in
which it is implemented, then the prototype should be placed into a /COPY
member and /COPY'd into both the original implementation module and any
other program/module that has a call to that procedure. 


I've seen another situation where someone illustrated how to use the same
source code to contain the implementation of the procedure and the
prototype, then depending on the result of /IF DEFINE statements, the
prototype XOR the entire source member was included.
-Hated that one too.

My opinion is that you should standardize on the above two styles. Don't try
to get too creative with other techniques because it will only confuse
people more. Having written hundreds of thousands of lines of C and C++
code, I can tell you, these two methodologies are the only ones I've seen
being used to any extent. 

-Bob Cozzi



-----Original Message-----
From: rpg400-l-bounces@xxxxxxxxxxxx [mailto:rpg400-l-bounces@xxxxxxxxxxxx]
On Behalf Of Christen, Duane J.
Sent: Wednesday, December 08, 2004 11:04 AM
To: 'RPG programming on the AS400 / iSeries'
Subject: Procedure interfaces and prototypes

I got this question from an associate today, I thought I would pass it and
my answer along for everyone:

Okay. I need advice...

"The procedure interface should be defined directly in the procedure, not
through a copybook. The compiler uses the prototype to verify that the
procedure interface is correct and is also used by the compiler to verify
that the calling program is calling the procedure correctly. If the
procedure and the calling programs use the same prototype from the copybook
they will always be right."

I get this, and I get that it is the way MOST RPGers handle it.  But I don't

understand it entirely, because it means interface vars have to be
maintained in TWO places, once in the copybook and again for the procedure
interface.  If, on the other hand, your copybook contains JUST the parm
definitions, that code can be included in all THREE locations, in calling
and called code (including PI defs).  This eliminates dual maintenance.  I
know everyone says the PI should never be changed, but get real--what do you
think?????



My response Below:
The statement "The procedure interface should be defined directly in the
procedure, not
through a copybook." is wrong, and right.

It is wrong if the procedure is to be a global procedure, available to be
imported into any program/sp/module.

It is correct if the procedure is to be local to the program/sp/module.

Lets say we have a math service program, SPMATH. In this math SP we have
some functions that other people need to access, these functions are:
add1ToVar, add2ToVar, multiplyVarBy10.
add1ToVar is in module MODA, it is exported from MODA and calls a procedure
getVarValue.
add2ToVar is in module MODB, it is exported from MODB and calls a procedure
getVarValue.
multiplyVarBy10 is in module MODC, it is exported from MODC and calls a
procedure getVarValue, it also calls a procedure multiplyVar.
multiplyVar is also in MODC, it is NOT exported from MODC. (It is not called
by any other procedure except multiplyVarBy10)
getVarValue is in MODX, it is exported from MODX. (It is called by many of
the math procedures, but it should only be called from math procedures in
SPMATH)

This is how I would put it together:
SPMATH exports add1ToVar, add2ToVar, and multiplyVarBy10. In other words the
binding source for SPMATH contains something like this:
STRPGMEXP  PGMLVL(*CURRENT)
EXPORT     SYMBOL(ADD1TOVAR)
EXPORT     SYMBOL(ADD2TOVAR)
EXPORT     SYMBOL(MULTIPLYVARBY10)
ENDPGMEXP

This makes the procedures add1ToVar, add2ToVar, and multiplyVarBy10 global,
available to be imported into any program/sp/module.

The copybook for SPMATH would contain prototypes for the procedures
add1ToVar, add2ToVar, and multiplyVarBy10 and would be /COPYed or /INCLUDEd
in any program/sp/module that needed to import them. (Including the modules
that export them)

Even though getVarValue is local to the service program it must be exported
from the module MODX, but it is not exported from the sp SPMATH because it
is not listed in the binding source so the modules MODA, MODB, MODC and MODX
would contain a copy of prototype for getVarValue, I would not have this
prototype in a copybook because it is local to the sp SPMATH.

The module MODC would contain the only prototype for the multiplyVar, and it
would not be exported from the module because it is local to the module,
only used by the procedures in MODC.



The procedure interface is a seperate entity from the prototype and CAN NOT
be in a copybook. If a procedure is designed correctly the interface, and
the related prototype should not change.

If it is necessary to change a procedure interface the change can be
implemented so that it does not impact any existing code. Lets say this
procedure, PROCA, is defined like this:

Prototype in a copybook:
procA           PI
                        10A   Value
                        10P 0   Value

Procedure interface:
procA           PI
field1          10A   Value
field2          10P 0   Value

Then lets say that we need to have another parameter field3, the interface
then would look like this:

Prototype in a copybook:
procA           PI
                        10A   Value
                        10P 0   Value
                         5I 0   Value Options(*NOPASS)

Procedure interface:
procA           PI
field1          10A   Value
field2          10P 0   Value
field3           5I 0 Value Options(*NOPASS)

In the code for the procedure PROCA you would have something like this:

If      %Parms = 3
        field3Value = field3
Else
        field3Value = 0
EndIf

What this does is: if 3 parameters were passed into the procedure then the
variable field3Value, which is used throughout the procedure, is set to the
value passed into the procedure. Otherwise the variable field3Value is set
to a default value which will be used throughout the procedure.

Ok so now lets do one a little more complicated, lets say we now need to
extend the parameter field1 from 10A to 20A, there are a couple of ways to
do this but they are all ugly, this is the way I would do it:

Prototype in a copybook:
procA           PI
                        10A   Value
                        10P 0   Value
                         5I 0   Value Options(*NOPASS)
                        20A   Value Options(*NOPASS)

Procedure interface:
procA           PI
field1          10A   Value
field2          10P 0   Value
field3           5I 0 Value Options(*NOPASS)
field4          20A     Value Options(*NOPASS)

In the code for the procedure PROCA you would have something like this:

If      %Parms >= 3
        field3Value = field3

If      %Parms = 4
        field1Extended = field4
EndIf
Else
        field3Value = 0
        field1Extended = field1
EndIf

What this does is: if 3 or more parameters were passed into the procedure
then the variable field3Value, which is used throughout the procedure, is
set to the value passed into the procedure. If 4 parameters were passed then
the variable field1Extended, which is used throughout the procedure, is set
to the value passed in for the longer field1 value. Otherwise the variable
field3Value is set to a default value which will be used throughout the
procedure and field1Extended is set to the field1 value.

This may seem rather ridiculus, and it is, but this is an example of poor
interface planning and I have done things like this in the past, some even
more rediculus.

If you are sure, and I mean SURE that the interface will not change then
passing individual parameters like this will work just fine for the
procedure, but if you are not sure or you know that in the future there will
be the need to "add" capabilities to the procedure then you need to designe
a flexable interface like this:

getCustomerInfo...
                PI
infoBase                  *     Value
infoFormat              10A     Value
infoLength              10I 0   Value
keyBase           *     Value
keyFormat               10A     Value
keyLength               10I 0   Value

We can talk about this later, I need to get back to work now.

Duane Christen



NOTICE: This electronic mail transmission may contain confidential
information and is intended only for the person(s) named.  Any use, copying
or disclosure by any other person is strictly prohibited. If you have
received this transmission in error, please notify the sender via e-mail.



--
This is the RPG programming on the AS400 / iSeries (RPG400-L) mailing list
To post a message email: RPG400-L@xxxxxxxxxxxx
To subscribe, unsubscribe, or change list options,
visit: http://lists.midrange.com/mailman/listinfo/rpg400-l
or email: RPG400-L-request@xxxxxxxxxxxx
Before posting, please take a moment to review the archives
at http://archive.midrange.com/rpg400-l.





As an Amazon Associate we earn from qualifying purchases.

This thread ...

Follow-Ups:
Replies:

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

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