Version: 2.00.00 - last update: Saturday, March 22, 2014, 12:30:00
This is all about how to avoid VFP's Macro Substitutions and other SLOW VFP commands, and how to substitute them with FASTER alternatives using VFP9.0
Intro
In case you do not already have noticed it, let me tell you again: I dislike VFP's Macro Substitutions! At least when they are used unnecessarily, because IMHO, this is either evidence for the lack of VFP skills, or even worse, intellectual laziness! In most contexts macro substitutions are superfluous! I will give you examples how to code it the right way instead of lazily using macros. But here will be more…
What will be in here
Beneath VFP's Macro Substitution there are a lot of functions and commands that run slower than others which do the same job in VFP 9. I will use this post to collect my findings, either found by myself, or found in the internet (then I will link to the source of course!), to give you a good starting point and a profound platform for your own 'native' speed optimizations.
What will NOT be in here
This is not the place to discuss the basics of good programming. E.g. we will not talking about FOR…NEXT loop constructs and that it would be better to initialize variables outside the loop to speed things up. I'll leave this trivia to the plethora of Beginners Books out there in the wild. Go and get one of these if you're just starting your career as a programmer…
Keep in mind: This is a VFP 9.0 blog! Sure, some VFP 9.0 functionality I'm talking about now wasn't available in older versions. Maybe you still have to use VFP 8.0 (or even 7.0) - What a pity! I do believe that most of us are using VFP 9.0 today. Thus, there will be no discussions in this post how to solve a particular problem with one of the older versions of VFP!
Please let me know!
If you have one or more good examples for speeding up your applications by simply replacing a slow VFP command with another faster one, please let me know! Please add a comment at the end of this post. I will review and add it when I'm going to moderate incoming comments next time.
Content
At the moment this section still is pretty disordered – I'm just starting to collect the tips. I will try to create some kind of useful categorization later.
Manipulation of variables
Example: Create a private variable with a name stored in a class property
* Instead of doing it the uncool way: Local lcName lcName = This.cVarName Private &lcName. * Code it short & sweet like so: Private (This.cVarName)
Example: Assign a value to the variable above
* Instead to prove your brain death: Local lcName lcName = This.cVarName &lcName. = "123456"
* Code it smart like this: Store "123456" TO (This.cVarName)
Note: Using parenthesis with VFP's STORE command tells FoxPro not to store the value to the memory the variable is pointing to but to the memory the content of the variable is pointing to. A regular variable is called a (named) pointer. What we get when bracketing a variable is a pointer to a pointer, which also is called a handle. You can assign a value to a handle using VFP's STRORE command only!
Restore Saved VFP Settings
Example: Saving Set("SAFETY")
Local lcSafety AS String lcSafety = Set("Safety") Set Safety Off *\\ Do wild things now *// and when done... * Instead of doing it the lazy way: Set Safety &lcSafety. * Code it running fast and keep it portable! If m.lcSafety == "ON" Set Safety ON EndIf
Note: You temporarily saved a VFP setting and changed it to the state you needed. If it is an ON/OFF setting you do NOT need a complete IF…THEN..ELSE construct during restore, but a simple IF…ENDIF only! What do you think runs faster in average? I mean there is a good 50/50 chance that you will not have to reset the setting at all because it was already set just the way you needed it!
Access Fields of an Aliased Table
Example: Read the value from a field named "PKey" of a table opened under an alias name stored in a property.
* Instead of taking the long way home: Local lcAlias lcAlias = This.cAlias Return &lcAlias..Pkey * Code it as a one-liner and win! Return Evaluate(This.cAlias+".Pkey")
Evaluate() runs faster than a Macro Substitution! Thus, you should always prefer Evaluate() to Macro Substitutions when dealing with table.fieldnames access!
<to be continued…>
Local lcSafety AS String
ReplyDeletelcSafety = Set("Safety")
Set Safety Off
*\\ Do wild things now
*// and when done...
* Instead of doing it the lazy way:
Set Safety &lcSafety.
* Code it running fast and keep it portable!
If m.lcSafety == "ON"
Set Safety ON
EndIf
Many times you don't know the final settings.
should be :
If m.lcSafety == "ON"
Set Safety ON
else
Set Safety OFF
EndIf
Which makes 5 lines instead of one !
execscript("set safety "+m.lcSafety)
Will do the job
Amos
This comment has been removed by the author.
ReplyDelete@Amos: Thank you for your interesting 'alternatives'.
ReplyDelete1st: Can you tell me a pairing of SAFETY (pre-)setting and a local re-setting of SAFETY, where my solution does NOT produce the same outcome (when returning from the routine the global SAFETY setting must be restored correctly)? I cannot! The core of my save/restore concept is that I do a SET SAFETY OFF just after saving the current global setting. This is my new 'local SET SAFETY setting' now. Naturally, the trailing code must respect this new internal setting accordingly (always restore SAFETY setting to "OFF" when finished)! Thus, my final m.lcSafety=="ON" test only has to compare the saved (global) setting with my internal (negated) setting.
2nd: Your Execscript("set safety "+m.lcSafety) definitely is slower than any odd macro substitution. But hey, its a one-liner - at least ;-)