Tips, Tricks and Gotcha's with VFP's SET PROCEDURE command
See also Visual FoxPro Invocation Stack
SET PROCEDURE is a very useful command for referencing procedure/function libraries. Just put all your really useful little routines into a .PRG file (or several, grouped by whatever makes sense), then
SET PROCEDURE TO util.prg, winutil.prg, clsutil.prg, whateverutil.prg and you can reference all of them as though they existed as individual .PRG files.
Whoa! Hold on! How often will the grouping make sense? Worse yet, what happens when the grouping no longer makes sense? Who wants to go through the hastle of reorganizing the grouping? -- Mike Yearwood
Considering long file names in the O/S, why not just make each routine its own little .PRG? Even without long file names, there is benefit to making each its own little .PRG. Remember, there are Fox people who only use the first four letters of commands. 8 character DOS files names is twice as good ;) -- Mike Yearwood
Benefits and detriments of using one or more procedure files versus many .PRG files for utility routines that can be shared across projects.
- Multitudinous Little .PRGs
- Flattens an otherwise complicated hierarchy of functions. -- Mike Yearwood
- If you keep separate .PRGs, you do not have to compile the entire library, then set procedure to that library in order to test/develop a routine. -- Mike Yearwood
- If you are tracing code in one procedure in BIG.PRG and you need to fix code in another procedure in BIG.PRG, you get in your own way. With separate little programs, you can usually edit any of them at any time. -- Mike Yearwood
- A small project will only have the PRGs it uses listed in the project manager. That would make it easy to locate the components. A large project will have many .PRGs, but that is no harder to work with than the Document View is now. Further, you don't have to try and figure out which procedure library contains the specific PRG. -- Mike Yearwood
- Safer because corruption of the large .PRG file would be a terrible loss. -- Mike Yearwood
- Reduce conflicts in multi-developer shops when 2 or more developers trying to check in different changes to the one .PRG.
- Multiple windows open showing different routines.
- There was a performance hit taken to SET PROCEDURE TO BIG.PRG, ( until VFP7 -- Mike Yearwood).
- There is(?) a performance hit to DO ROUTINE IN BIG.PRG.
- No difference in performance between calling routines in a big .PRG and calling routines individually when built into an app/exe (except of course the hit to say SET PROCEDURE TO) ( again until VFP7 -- Mike Yearwood)
- No need to recompile the entire big .PRG when recompiling one little .PRG will do.
- Exe is smaller because unused items are not included. They would be included without exception by using BIG.PRG.
- Early operating systems limited filenames to 8.3 characters. Some used procedure libraries to get around this limitation because FoxPro would allow you to code really long procedure/function names, but since FoxPro only respected the first 11 characters, this was a little risky. -- Mike Yearwood
- Prevents multiple procedure files from having identical (or worse nearly identical) functions! -- Mike Yearwood
- If a .PRG is used by an index, you can open the table just by having the .PRG in the path, no need to SET PROCEDURE or SET DATABASE etc. That can make quite an impact when a UDF is part of an index expression. -- Mike Yearwood
- If not using an app/exe, performance hit taken by O/S to find the individual .PRG - mitigated by caching. The whole point is to program for the runtime environment - that is the exe. To performance test the exe, put it in a clean environment. Don't try to performance test in the development environment, because it's really the exe performance that matters. -- Mike Yearwood
- Need a project wide search routine (like GREP, though GREP won't (cleanly) look in VCX's) to find a common string throughout many files. GREP in VCXs is not relevant to this topic. I'd like to see a similar discussion comparing one class per class lib versus multiple classes per classlib ;) -- Mike Yearwood. See VFPSet Classlib
- Might be seen as cluttered by some. Mitigated by the next 3 points ;) -- Mike Yearwood
- Must copy many files to share all the utility routines. Mitigated by having a PRG that lists individual routines and using the Project Manager. -- Mike Yearwood
- Harder to make sure that a particular project has ALL the latest versions of the utilities. Only if the routines are reference by indirection. The Project Manager would include them automatically.
- Procedure files
- Can share a standard library of utility routines
- Can easily import many useful functions at the same time ... establish an expanded "vocabulary" in foxpro that is available to any application developed in the same shop. The Project Manager will take care of this for you. -- Mike Yearwood
- Increases dev time. Each change to a routine in a library, means you must compile the entire library and then SET PROCEDURE to that library just to test the change. -- Mike Yearwood
- Harder for multiple developers to work on different routines at the same time.
- Whole file is included in project whether all the routines are used or not.
- When one procedure in a procedure library exceeds the 65K compile limit, it is difficult to determine which procedure has the problem. With separate .PRG files, it is obvious.
However, the VFP File Search Path (looking for which .PRG file the SET PROCEDURE command is referring to) gets a little complicated when you have multiple procedure files by the same name but in different places, or multiple procedure files in .APP files.
Currently I'm still trying to make sense out of this, and so these answers are not yet complete, but here are some of the complications:
The main program (.PRG during testing) issues:
SET PROCEDURE TO UTIL,COMMON
Then calls an addon program's (.APP file) initialization function:
DO Register IN message.app
This function issues some of its own commands:
SET PROCEDURE TO mess.prg ADDITIVE
( this has at times been tried as SET PROCEDURE TO mess.prg IN message.app ADDITIVE )
If this .APP file also has a file UTIL.PRG inside it, it may issue:
SET PROCEDURE TO util.prg ADDITIVE
and this overrides the previous UTIL procedure file (instead of adding to the the search path anything that may be new in this one.)
Also the syntax:
SET PROCEDURE TO filename IN AppFile.APP ADDITIVE does NOT give a compilation error or a runtime error, but it has the result of releasing all the other active SET PROCEDURE files (ie: the ADDITIVE keyword is ignored) and changes the SET PROCEDURE setting to "filename.fxp" and DOES NOT PROVIDE ACCESS TO ANY ROUTINES IN THE FILE (either the filename.fxp outside the .APP or the filename.fxp inside the .APP).
What about OOP?
It might be instructive to consider creating a custom object (or session object) with mulitple methods as a third alternative. The object (perhaps named udf) would be created in your main.prg and be accessed thereafter. A useage example would be udf.myerrormethod(). Here are some pros and cons I have thought of:
- Can take advantage of inheritance by having a general set of functions and then subclassing it in order to incorporate a set of application specific functions.
- Considerations and complications for the Visual FoxPro Invocation Stack are eliminated. Also ensures that the sub-classing rules take care of duplicate named functions within the class structure.
- Take advantage of the class editor when creating/editing the methods. - That is no different than the code editor. -- Mike Yearwood
- The methods in a class can have a state through the use of properties in the class; whereas a procedure file/PRG function is stateless. Example: your udf.logon() method remembers who logged on by creating a udf.whoisloggedon property. Then when you call the udf.logoff() method it knows who is logging off.
- You are an OOP nut that loves making everything a class.
- Can take advantage of the session baseclass and have methods that manipulate tables without being concerned about the datasession that is calling the method.
- Must create an object memory variable to use the methods within. You have to be careful with using PRIVATE ALL since it would block access to the object.
- May (or may not) be a performance issue versus a pre-compiled procedure file. (Actually there is a greater than 5 times speed loss vs calling a single function --MikeYearwood)
- Has the same issues as a procedure file with regards to managing multiple methods in a single file.
- Multiple developers cannot work on this class simultaneously without some source control tool.
-- Ben Creighton
Contributors: wgcs, Mike Yearwood, Ben Creighton
Category VFP Commands Category Performance
Category Needs Refactoring
( Topic last updated: 2017.12.13 04:55:27 PM )