Using concepts learned from the famous IBM Red Paper on RPG Exception and Error Handling, I have written a service program QGPL/ERRFUNC
to implement reusable error functions like Assert
, Throw
, ThrowMsg
, Rethrow
, and GetErrorMsg
. I have been using these in several different programs and they have been working well.
Just now, I have used the Throw
function in an RPG ILE program that also statically calls the C-style function access
that is used with stream files on the IFS file system. That program will not compile with a binding error of "Definition supplied multiple times for symbol Throw". As far as I know, you cannot get the binding detail when compiling using the CRTBNDRPG
command, but I was able to comment out my H DFTACTGRP(*NO)
spec and then compile it using CRTRPGMOD
followed by CRTPGM
with the additional parameter DETAIL(*EXTENDED)
. This prints out an extensive list of all the procedure names that the compiler looks at when determining what procedures to statically bind to. This revealed the double definition of "Throw". Deep inside the 72 page listing, the IBM supplied service program QJVAJNI
(Java Native Interface) was referenced and it contains an exported procedure also named "Throw".
Now the easiest fix for my immediate problem would be to simply rename my "Throw" procedure, revise and recompile my service program, and then revise and recompile all the programs that reference it. I may follow that solution, but there are several troubling questions raised by this behavior:
Why does a C-style IFS function make use of the Java native interface to get its work done? I see imports of service programs like QC2IFS
and QC2POSIX
that totally make sense in context. It looks like IBM introduced an unexpected dependency here that we have to live with. I am certain that it is one of the C service programs referencing the QJVAJNI
because when I comment out the access
function call, the QJVAJNI
does not get referenced. It is possible that the reference to the QJVAJNI
service program is several layers deep, meaning the import of an import of an import.
Why does the binder recurse so thoroughly through service program imports? The binder looks like it goes through every import that each service program uses, whether or not that import is used by the program and subprocedures being bound. Is that necessary? Wouldn't it work to recursively check only the imports that are used at each level? Is there a way to change this behavior?
If there is nothing that can be done about the above two questions, does that mean that to guarantee that binding will always work (especially for "general purpose" functions like error handling), one must be sure that there is not any other exported procedure anywhere on the machine with the same name? I am not aware of any facilities like namespaces that would alleviate this problem. As far as I know, the ILE compilers don't use any approaches like overloading or name mangling that other platforms might use in this situation. Would it be a good practice to start "informal namespacing" like I can see on some of the C exports (e.g. _C_NEU_IFS_feof
) to prevent name conflicts? Alternatively, is there a way to search all exported procedures on the machine to look for your desired name before publishing a service program?
The authors of IBM Red Paper are some heavyweights in the world of ILE programming. They named one of their recommended exports "Throw" like I did (although with a different parameter list). Did they run into similar problems? Did they have a different way to resolve the name conflict?
I have found that there is an option *DUPPROC
one can specify for CRTPGM
, but I am not sure that is a good idea. The documentation says "When multiple duplicate procedures are allowed, the first exported procedure in the list of specified modules and service programs that matches the import request is the procedure that is selected." Can you be sure which symbol is going to be first in the list? Is the ordering strictly defined?
There is no namespacing in RPG, or C for that matter. When you bind ILE programs, the binding directory controls which service programs (and modules) are used to resolve names. It is not every service program on the system. But there are also some service programs that are bound in by default, and if you use a name that is exported by one of these automaticly bound service programs, you will have issues with duplicate names. You are right, *DUPPROC
is a bad idea. The only way to deal with names that duplicate procedures in the automatically bound service programs is to not define new procedures with those names. Some follks use pseudo namespacing techniques like serviceprogramname_procedurename
or applicationprefix_procedurename
when naming their procedures. Others just make sure their procedures have unique names by other means. But until RPG supports some form of namespace, you are going to have to use some kind of arbitrary naming scheme to ensure uniqueness of procedure names.
BTW, there is an RFE at developerworks to add namespaces to RPG. You need to be signed in to developerworks for the link to work, but you can register for free. Then visit the RFE and vote for it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With