Another question I have been researching since long.
An external subroutine has access to both PDA and GDA while Subprogram can only access PDA then what is the need of a Subprogram? Why don’t we always use Subroutine?
Both external subroutines and subprograms lend themselves to putting business logic that is shared between other program objects in a common place and lend themselves to reusability and ease of future maintenance. Just as you know there are times an external subroutine is more desirable and appropriate, such as inside a single application with multiple objects needing to perform common business logic, there are times where a subprogram is more suitable.
A subprogram functions in a much more standalone manner. It does not inherit the calling object’s data area and so it does not have access to the calling object’s variables and their values (which may be why you find them advantageous). You must pass in through a PDA any values you want it to have access to. However, when you have a need to make a common routine called from multiple applications, this becomes more of an advantage because different applications are likely to use a variety of different variables for many purposes and you will likely have very little need for anything other than the values of context to the function of this specific routine. A subprogram can define locally any variables and views that it needs to perform its function, and you do not need to worry about whether the same views or variables are defined in calling objects and what values they have as there is no sharing of this between them, preserving the integrity of each. An inadvertent changing of a shared view or variable in a subroutine that is used by one or more calling modules but not others can create some very unexpected and catastrophic consequences.
Subprograms can be extended well beyond just the Natural environment via EntireX (e.g. exposed as a web service) because of it not needing external context to function other than what is specified as its PDA.
Hence, there are many reasons to use subprograms instead of external subroutines which is determined by the nature of which you wish to reuse the code.
As Brian says, a subprogram is more of a standalone object. You can share a subprogram across application libraries quite easily from a shared steplib. An external subroutine that references a GDA will be limited to be called from modules that use that GDA (which is typically an application-library specific module).
I think there is a performance aspect on using external subroutine vs sup programs.
When we access a external subroutine, by the subroutine name, during runtime, system had to search all external subroutine modules to locate the subroutine. Where as in the case of a subprogram, the call can directly link to the name of the module(not a string within the module).
Natural must have some indexing mechanism to make external subroutine access faster, but still it would require bit of extra processing to locate it as compared to Subprograms…
As far as I know subroutine objects are located at compile time, not runtime. You cannot use a variable subroutine name for example (PERFORM #VARIABLE-NAME) which you can do for a CALLNAT. So as soon as your ‘performing’ module is stowed, the link to the module containing the external subroutine is fixed.
The differences between all these external ‘routines’ can be subtle sometimes but they are still significant if you know Natural well enough. The fact that an external subroutine uses the same GDA as the calling module can be an advantage or a big limitation, depending on your situation.
Some people value their data ‘safety’ and would not like it if all external modules could just change any of the variables defines in the main module. Subprograms can only change what you give them via the PDA, nothing else. When you pass by value they cannot even do that.
But if you try with compiling an external subroutine, which does not exist in the system, then the code compiles ok. So I think the link is established at runtime and not at compile time.
When an external subroutine is CATALOGed, an entry is made in an internal Natural table in FUSER. The entry contains the routine’s long and short (module) names. When a calling routine is CATALOGed, that table is searched. If the subroutine name is found, the short name is inserted into the calling routine’s object. At execution time, if the calling routine does not contain the short name, the table is searched. So it is best to compile the subroutine prior to compiling the calling routine, to avoid table look-ups at execution time.
As to Shashank’s question, there are no restrictions on the data defined in an external subroutine (LOCAL, views, etc).
As for Shibu, subroutines are faster when there are no parameters passed (because the variables are in the GDA). Subprograms invariable require a parameter list and on each call Natural checks number of parameters and each format/length.
Middleware applications and Enterprise Service Hubs can invoke a SubProgram direclty but they cannot invoke a Subroutine. That’s a good enough reason I guess.
Yes, thats another good remark. You can expose a subprogram as a service (e.g. via NaturalONE EntireX generate web service function) and you cant do that with a Subroutine.