FAQ's - APPX Software, Inc. : Trash :
152 - GOSUBs and SUBRoutines | |
When a GOSUB statement references a SUBROUTINE process, the SUBROUTINE code gets included in the current event point when the process compiles. If the code looks like this:
..GOSUB ABC VALIDATE ORDER..[END] ENDLABEL {system generated label}COPY ABC VALIDATE ORDERRETURN[END] So, as you can see from this construct, you may fall out the bottom of the SUBROUTINE process and be automatically returned to the statement following the GOSUB, or you may use a RETURN statement to exit early from the SUBROUTINE process. It is not normally a good idea to ever use an END statement from a SUBROUTINE process that will be encapsulated within another event point using GOSUB or COPY statements. If the SUBROUTINE process is called using a SUBR statement, then END is a natural exit. SUBR calls execute the SUBROUTINE process as a stand alone process instead of inline code. This means that the END only ends the SUBROUTINE, and has no effect on the calling event point. There is a balancing act to using GOSUB or SUBR to execute code. When using a SUBR for everything, lots of small executable modules have to get swapped around in memory and on disk, so GOSUB is a faster performer on the system. However, SUBR creates more isolation from the parent code. RELATED and DETACHED invocation can be used to prevent sharing of fields so you don't have to worry about stepping on work fields, and it also allows recursion. Another benefit of using SUBR is that it creates a new STORE/RESTORE buffer in the SUBROUTINE process (since it is a separate process). This means that even calling it as a SUBPROCESS invocation type, you have the benefit of being able to STORE things like TEMP 80, use it, and restore it without having to worry that you may be stepping on a STORE of TEMP 80 done in the parent code. In fact, it is sometimes a good idea to STORE all work fields at the beginning of a SUBROUTINE that you will be using, and RESTORE them at the exit point. That way when you do a SUBR call, you do not have to worry that a work field is being reused and getting stepped on.
So, the big difference is that GOSUB copies in the code at compile time, and SUBR executes the code as a separate process at runtime. "Wondering why a routine had gotten slower than the last time I used it on any reasonable number of record, I replaced the SUBR with a GOSUB & COPY combination.
With SUBR = 138.11 seconds
More than two orders of magnitude difference. Something to consider avoiding inside of loops."
"I recently found that if you have a subroutine in a subroutine process and then call the process with a SUBR verb you end with error messages during runtime and compilation. Change that call to a GOSUB and these problems went away." Not surprising. When you use a SUBR, APPX has to go thru the overhead of starting a entire, new process, and then, when it's over, go thru the overhead of returning control to the calling process. If a GOSUB or COPY will do, then use that, not a SUBR. However, there are times when the fact that it is a SUBR lets you do things you might not be able to get away with otherwise.
I had a situation where I was reading a file by a NAME key, using BEG READ/END READ. When I found a record, I had to start another BEG READ/END READ on the same file, but by a different key. Normally APPX doesn't let you nest BEG READ/END READs on the same file, but by putting the second one in a SUBR, I got what I wanted. About the only use I have found for it would be the rare instance when you would want to recursively call the function from within itself. I think the last time I used it was in a program that exploded the Bill of Materials for an item.
It is a lot slower than GOSUB because it is self-contained and there is a lot of overhead involved when calling it. GOSUB just copies and executes the code in-line with all the rest of the Event Points code. Also, don't forget that GOSUB/COPY handles T/F flags differently than SUBR. Using a GOSUB stores the flags of the calling process before running the subroutine, clears them at the start of the subroutine and then restores them after the subroutine completes. The subroutine will then use its own set of flags without impacting the ones from the calling process. On the other hand, SUBR will not save the current state of the T/F flags when the subroutine is run, and the code in the subroutine can perform activities based on the incoming flags, and can modify them as well. After the SUBR commend is performed, it sets on the next T or F flag to T if the process invoked properly, or to F if it failed.
Therefore, if the code in your subroutine will depend on the state of the flags in the calling process, or if you want the subroutine to modify those flags, you will want to use the SUBR verb."
| |
[Append to This Answer] | |
2010-May-20 12:29am |
Previous: | 584 - Diagnosing Strange and Generic Errors |
Next: | 171 - APPX Process Stack (TABLE) |
|