Stanlyn,
To understand all these "methods" (meaning, ways to accomplish things), you need to understand a bit more about the way things work also.
Variables are either a) passed by value or b) passed by reference. These various means of "macro expansion" as you mention may or may not be necessary depending on the scenario.
There are many who will shun the use of & (Macro Substitution) particularly in the VFP space, but the reason it is prevalent here has it's roots in FoxPro before it was an object oriented language (and was and still is an event drive, interpreted language). Event driven is the "forerunner" of object models and FoxPro was one of the languages available in this "before OOP" that took advantage of it. As a result, macro substitution became prevalent, and despite what others will say, it's not *that* horrible.
So let's take example 1 and 2 in your list.
1. lcVariable - this is a typical variable, store a value a reference to the value. Variables are just that -- references. So hence the, "pass by reference" phrase you may hear from time to time. Arrays are also references to variable sthat include a "vector" -- a means of specifying WHERE the variable is in a "list" (for simple terms). So to expand on this example your lcVariable could just as easily be laVariable (note that I'm using "lc" and "la" as convention for naming only, they have zero baring on the actual references or type of variable they store, there "l" helps the developer understand the intended scope of the variable "l = local", and 2nd character they type "c = character" and "a = array". But these are only for ease of reference in code, and can be changed unintentionally, so be careful).
So in a practical usage you may say something like lcVariable = mytable.myfield and what happens then is, a variable named lcVariable is created by VFP and whatever the contents of mytable.myfield are get ASSIGNED to that variable (where = is the "assign" operator). Memory is used to hold the contents. Let's pretend for a moment that the value is the word "OFF" (I have a reason for this later).
So now if you were to put in code that says MESSAGEBOX(lcVariable) VFP would return to you "OFF". This is passing the variable by REFERENCE to MESSAGEBOX. It's "by reference" because we give the function just the variable name, and it uses it. MESSAGEBOX() is a pretty clever function, because it also doesn't care what data type is passed to it (as a single variable), it will determine what it is and display it for you.
Another way is to pass by VALUE. Value is just what it sounds like. Instead of passing the variable name, you actually shove in the "value". So, when we consider the example so far, there is a VARIABLE called lcVariable. It's VALUE is "OFF" (which we assigned to it from a field in a table).
Now, the "Macro Substitution" part does just what the latter part sounds like as well "SUBSTITITES" (in this case, puts the VALUE there, not the reference to the value.
So interestingly then with MESSAGEBOX, if you called it this way: MESSAGEBOX(&lcVariable) you would get an error. What VFP "Sees" in this case is actually MESSAGEBOX(OFF) the "macro substitution" gets literally interpreted by VFP as what the value of the variable is. Now, you can see a new behavior if you were to issue MESSAGEBOX("&lcVariabl") you will again get a messagebox display that just says OFF. What VFP sees in this case is MESSAGEBOX("OFF") so it prints OFF as we would expect to see.
So in your examples 1 - Is typical variable 2 - Macro Substitution (noted by the & added to ANY variable name) and your 3rd example is NAME SUBSTITIUTION.
Name substitution actually works almost exactly like macro substitution, but has a couple of advantages 1) it's "faster" (we're talking milliseconds) and 2) it works with more complex expressions, but 3) doesn't work with every case that macro substitution would... there's some reasons for that.
So if you're working with a form, let's say you create an property for an object. So that object is now referenced by it's path. myobject.propery for example.
Now thinking back to variables again, and passing them by reference, or value (and there by substitution methods in many cases) not all substitutions work the same way.
Put into context. I have a variable in my form that holds the name of the primary table I use in that form. So ThisForm.ActiveTable I can assign with ThisForm.ActiveTable = MyTable
To make this reusable across every form I use, and I don't have to reprogram the table name every time, I then use that reference in my code (especially for things like navigation button).
So now instead of in code entering SELECT MyTable (which is a "hard coded table name") I can say instead SELECT (ThisForm.ActiveTable) -- note here, I am using NAME substitution, which is noted by the () that are not a Function. (If it were a function it would be SELECT(ThisForm.ActiveTable) but SELECT is a VFP function that puts the workarea on the focus table (by many means). BUT, I bring this up because & substition will NOT work in this case. Because it would then have to be SELECT &ThisForm.ActiveTable and & works on the VARIABLE name that follows, this is an OOP relationship instead. SO another substitution method is needed. This is because SELECT expects to see either the work area number (litteral) or workarea name (litteral) and is why you don't "" it. So for example, using MyTable as the table name, you could:
SELECT MyTable
SELECT (Thisform.ActiveTable) (where "MyTable" has already been assigned to the property -- VFP Sees SELECT MyTable - after the substitution takes place)
Now concerning EVALUATE() function, this works different still.
If you issue:
SELECT EVALUATE(ThisForm.ActiveTable) VFP will generate the error "Variable MyTable is not found."
Which is an interesting clue about what's happening here... because EVALUATE is trying to pass a REFERENCE to SELECT and NOT a VALUE.
So NAME substitution works by passing the VALUE, EVALUATE returns the REFERENCE which works with functions that pass/share information by reference. So each of these have a different purpose, and are used differently. If we assigned lcVariabe = "MyTable" then:
SELECT (lcVariable)
or
SELECT &lcVariable
provide the same result, but the argument is that () Name substitution is faster than & Macro substitution.
There are times when name substitution doesn't work, and you need a different method. In these cases macro substitution may be necessary, EVALUATE is not an automatic "fix" to & (macro sub) nor is Name substitution. In many cases the "variable" will do fine, but that's a time where the function/call/command is expecting to receive a variable reference instead of a literal.
If you inherit code, or have to deal with backward compatibility, & is your best friend. I do find it comical the number of fox developers who harp on the & usage, and then find them running multiple DO LOOPS in succession which adds enormous amounts of time onto the run time. IF you're doing everything else right, the usage of & will matter ONLY when you have extensive loop processing where the code gets called over and over. The key thing here is because VFP has to process it every time, whereas with NAME substitution, at run time, it manages it differently in memory, and as a result once the expression is "unpacked" it keeps that in memory. With Macro it unpacks every time... HOWEVER... there may be clever/tricky situations where you want this behavior. If the value utilized by & in the loop changes, then the only way you'll get an unpacked change is with macro sub.
Hope that helps.
Best Regards,
Scott
ATS, CDCE, CTIA, CTDC
"Everything should be made as simple as possible, and no simpler."
![[hammer] [hammer] [hammer]](/data/assets/smilies/hammer.gif)