lcVarName (local, character, VarName)
tuVarName (parameter, undetermined, VarName)
Microsoft has programming standards documentation that describes all of its suggested prefixes. Much more informative and easier to read than m. all over the place. Ray Kirk
Best coding practice: Use both m. and hungarian notation. Readability is in the eye of the beholder. m. all over the place just takes some getting used to. See Essential MDot for more information. Mike Yearwood
Beware comments that end in a semicolon.
In VFP7 (and before?) the following code will only print "Hi"
* This is a comment ending with a semicolon ;
? "This won't print"
The comment is continued into the next line. While this is nice as it allows you to comment out entire statements like:
* SELECT * ;
FROM MyData ;
WHERE .t. ;
INTO CURSOR TEMP
With a single *, the Editor in VFP7 (and some beta's of VFP8 it seems) does NOT colorize the commented code as such.
This means comments ending in ; can lurk for years waiting to attack when the whitespace below them is removed, causing all sorts of possible odd compile errors (consider what may happen if the next line is
DEFINE CLASS... , or worse, no compile error, consider if the comment was at the end of an oft called UDF, followed by another, not so frequently used UDF:
Well! I'm a big fan of granularity. Instead of arbitrarily putting all your UDFs in one PRG, make each one it's own PRG and you'll never experience that! See VFPSetProcedure -- Mike Yearwood
Many people have gotten bit trying to embed the 'comment command' in a string:
? "&&" gives you Error# 36, "Command contains unrecognized phrase/keyword." because VFP sees 2 things: the code to execute:
? " and a comment right after it:
&&" - workaround:
DELETE doesn't delete. It just marks it to be deleted by the PACK command, which in a 'normal app' (multi user) doesn't happen till way later (sometimes weeks.)
You can SET DELETE ON which kind of hides the records, but they are still there and will block a candidate key if it is the same as what was deleted. And then there are the exceptions to this, which are explained in the docs. The best way to think about it is: you can't delete a record instantly. You can set a flag and the rest of your code should respect that flag. VFP gives us some commands to help, but you must still be aware that the record is there.
The value RECCOUNT() returns isn't affected by SET DELETED and SET FILTER.
Col = CREATEOBJECT("Collection")
? Col(1).Name && Error# 1230, "Too many arguments."
That is because col() is a vfp function. I think the Col= should have errored with a "reserved word" error, but there is no such error, and it would probably blow up too many existing apps if one was added.
> Along the same lines I also had problems when I used properties of the
> object that matched VFP names like Name. changing Name to cName fixed
> that as well.
I am guessing it is because VFP only needs the first 4? chars to 'identify' a reserved word, like TableUpdate()....
Whatever it is, VFP is not good about policing what are used as identifiers. To help deal with this, try to name your things something that doesn't stand a chance of being a reserved word. Most Naming Conventions take care of that for you.
Use "m." (? m.Col(1).Name), if you (stupidly!) insist on using reserved words for variables! The idiosyncrasy here is that VFP allows you to use reserved words for things - but this is for backwards compatability. C++ programmers wouldn't try to name a variable "int"! -- Peter Crabtree
Macro substitution is powerful but has some not so easy to understand idiosynchracies. Specifically the need for an extra "dot" to delimit a macro-expansion variable when another dot is required.
cFileName = "ABC"
cSequence = "1"
* file exists
* file not found
In the example above two dots are needed, one to end the macro expansion, and one to literally add a dot for the filename. If you had used only one dot, it will be "eaten" and considered the as end macro of expansion marker.
Best answer to that is to always end every macro with the termination period. Mike Yearwood
Note that in this case there is a more straightforward and cleaner way of referencing this filename:
IF FILE(cFilename + cSequence + ".DBF")
* file exists
* file not found
Activepage in a Page Frame is not the index of the active page in the pages-collection, but the pageorder of the active page. As long as you don't resort your pages everything is ok...
Look at: Page Frame
When is something plus null not null? When that something is a string more than 100 characters in length. E.g.
x = replicate('x',100)
x = x + null
?x && returns null
x = replicate('x',101)
x = x + null
?x && returns xxxxxxxxxxxxxxxxx...
Is there a reason for this? Rhodri C Evans
x = replicate('x',101)
z = x + null
?z && returns null
Does this sound buggish?
It probably is a bug ... a long standing one, I can demonstrate the weird behaviour in VFP 6,7,8 & 9.
Note also that
x = replicate('x',100) + null
?x && returns null
works as expected.
Sounds like the VFP code to add to a string variable is bugged, not the code to add two variables together. (In other words, when VFP does x = x + y, then, internally, it becomes "x += y", which uses different code than "x + y". -- Peter Crabtree
TRY .. CATCH and SET CONSOLE
SET CONSOLE is changed to ON whenever an error occurs regardless of whether the error is trapped by a TRY .. CATCH. The help on SET CONSOLE only says "An error always sets SET CONSOLE to ON." but why would you want this behavior? Can anyone explain why this happens? And are there other settings that are automatically changed when an error occurs? -- Tom Bellin
Tom, just ran into this myself. You're right, I can't think of why I would ever want SET CONSOLE to be ON in my app. Therefore, I've searched all my projects for TRY/CATCH and have issued a SET CONSOLE OFF immediately following any code in the CATCH portion. Good "catch" man. -- Randy Jean
- If you attempt to set the grid's columncount property equal to zero from a contained column or header object method, it will delete all but the column where the method is. For example, if you create a click method for the header that redefines the grid, setting columncount=0 inside that method will not eliminate the column where that header is located, but will eliminate all other columns. Solution: redefine the one remaining column instead of treating it as deleted.
- Prior to VFP9, do not use SET FILTER TO on a large table that is being displayed in a grid. It can take a VERY long time to refresh the grid. I have seen this behavior in tables with as little as 10,000 records. If possible, you can use SET KEY TO without performance problems or better yet, use a SELECT statement or a view. By the way, I have not used VFP9 but apparently grids now can use rushmore optimization with SET FILTER TO if the grid's optimize property is set.
- Grids automatically refresh themselves on frequent intervals to keep the rows of data displaying the correct and current data. This means that if you are simulaneously updating a row that is also displayed, you can experience locking conflicts. The workaround is to set the form property lockscreen=.t. in the form that contains the grid to prevent the grid from refreshing while your updates are being made.
- A Textbox object in a grid column will allow you to click directly into the middle of a displayed number or character string. In many data entry scenarios, clicking into the middle of an existing number in a Textbox and then trying to type a new number is fraught with error and frustration since you are not typing over the entire number, just the last few digits of it. To eliminate this problem, use the following code in the GOTFOCUS event of the textbox.
You should include "K" in the format property of the textbox.
Now when you click on the textbox, it selects the entire contents of the box. When you start to type, the original number is completely erased and you starting from the leftmost cursor position. This trick also works for textboxes outside of grids. In addition, if you click a second time on the same textbox, you will still be able to place the cursor mid string or mid number if you want to. -- Ben Creighton.
Another Grid Gotcha
Grids do not respect SET RELATION TO.
For example, I have parent table alias PARENT1 and a child table alias CHILD1 ordered by the foreign key for PARENT1. I select PARENT1 and set relation to PRIMARYKEY into CHILD1.
Now set the grid's RECORDSOURCE property to PARENT1 and use any field from CHILD1 as one of the column fields. Note that the record pointer doesn't change in CHILD1; you get the same value for the column throughout the entire grid.
Solution: Create and use as the CONTROLSOURCE a UDF that changes the record pointer in CHILD1 and returns the field data. So sorry if you wanted to actually edit the CHILD1 field. -- Ben Creighton
nvl(x,y) and evl(x,y) always evaluate both x and y regardless of the value of x. It's like they have been implemented as UDFs, rather than as language components. -- Rob Spencer
Contributors: Carl Karsten Sergey Berezniker Peter Crabtree Alex Feldstein Mike Yearwood Rhodri C Evans Rob Spencer
Category Needs Refactoring