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
andQC2POSIX
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 theQJVAJNI
because when I comment out theaccess
function call, theQJVAJNI
does not get referenced. It is possible that the reference to theQJVAJNI
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?