|
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 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.