"It's a Feature, Not a Bug"
It's not surprising that a language with as many different roots as FoxPro has a number of odd behaviors—things that make you say "hmmm." Some of them, of course, are bugs. But this section is dedicated to those that really aren't bugs—the ones for which there's a legitimate explanation. You'll also find a number of these items in the Reference section. Often, you'll find a design icon next to them.We'll Continue to Try
Comments and continued lines can get you in trouble. On the whole, the trouble isn't as severe as it used to be (before VFP 5), but you can still get yourself in trouble.The problem comes up when you put the continuation ";" after a comment. The next line is still considered part of the comment, even if it doesn't start with a "*". So, the following:* This is the comment before the command ; SELECT Something FROM SomeWhere INTO SomeOneis actually treated as a comment. The query never executes.Personally we like to put a "*" at the beginning of each line of a comment, but there is a situation in which we find the above behavior pretty handy. Sometimes, we need to comment out a command for testing purposes or because we've replaced it with a new version. If the command is continued onto multiple lines, it's sufficient to just stick a "*" in front of the first line. Of course, starting in VFP 5, it's easy enough to highlight, right-click, and choose Comment, too.In VFP 3 and FoxPro 2.x, there's another situation where continuation can get you in trouble. You can't put in-line comments on a continued line. That is, lines like:
SELECT Something ; && here's the fields FROM SomeWhere ; && and the table INTO SomeOne && put it herefail because FoxPro just drops the ";" and concatenates the whole thing into a single line. This behavior was changed in VFP 5 to our great relief.
But There Didn't Used to Be a Syntax Error There!
When people started running existing applications in VFP 5, lots of them started seeing syntax errors in code that had been running for years. The code hadn't changed, so what was going on?Way back in Xbase history days, someone decided that you should be able to put comments on the same line as the structured programming commands without having to use the comment indicator. That is, you could write:IF x<3 Fewer than three remain ... ENDIFThe rule applied to each of the components of the branching and looping commands (IF, DO CASE, DO WHILE, FOR and SCAN). In fact, we have little doubt it was really set up this way so you could write stuff like the following (by the way, the dots used to be required around the Boolean logical operators .AND., .NOT. and .OR.):
DO WHILE .NOT. EOF() * process records ENDDO WHILE .NOT. EOF()It looks real nice, but it turned out to cause a rather nasty, subtle problem. When FoxPro parsed one of these lines, it stopped as soon as it reached something syntactically incorrect. That's right, as soon as the parser found a syntax error, it figured it had a comment and gave up. Consider, for example:
IF x<3 .AND y>7As far as versions of FoxPro through VFP 3 are concerned, that line only checks whether x is less than 3. The second part of the condition was totally ignored.VFP 5 changed the rules. You're still allowed to include comments without an indicator on lines that don't have any executable code (like ENDDO, ENDIF, DO CASE and so on), but if a line contains code (like IF or DO WHILE), the whole line is checked. Since we think the original design decision was terrible, we're delighted by the change. Anything to help root out stubborn hidden bugs is welcomed.By the way, the parser got stricter in other ways as well. Used to be that extra right parenthesis at the end of an expression were ignored. No more. Starting in VFP 7, spaces are no longer allowed to separate variables in LOCAL, PUBLIC, PRIVATE, LPARAMETERS, or PARAMETERS statements (for example, "LOCAL MyVar1 MyVar2" is now a no-no). In general, from VFP 5 forward, the compiler does a better job of finding syntax errors and ensuring that you're running the code you think you're running.
The Single Letter Blues
On the whole, the designers of Visual FoxPro have done a tremendous job marrying object-orientation to Xbase. But there are places where the marriage seems a little rocky. The use of single-letter identifiers is one of them.Traditionally, the letters A through J are alternate names for the first 10 work areas. (When the number of work areas went up to 25, Fox Software didn't extend this convention. It's just as well—they'd have a heckuva time finding 32,767 different characters to represent the work areas in Visual FoxPro.) In addition, the letter M was reserved to indicate that what followed was a memory variable. So, how would this cause you any trouble? Well, what if you have a table named C.DBF? When you open it with USE C, you'd expect it to have the alias of "C", right? Only if you're really lucky. Because "C" is reserved for the third work area, the only way C.DBF will have an alias of "C" is if you open it in the third work area. Otherwise, it'll have an alias of the work area it's opened in ("A" through "J" if it's opened in one of the first 10 work areas, or "W" followed by the work area number if not). So, when you use code like SELECT C to select the table, you'll really be selecting the third work area, which may have an entirely different table open or no table open at all.OOP makes it even worse. Object-orientation uses the same type of "dot" notation that fields in tables do to spell out the complete name of an object, like frmMyForm.grdMainGrid.colName.txtName. So what's the problem? There is none, unless you try to use one of the letters A-J or M for the name of an object. Code like the following:a=CreateObject("form") a.Caption="My Form"is doomed to failure. You can create the form, but the assignment blows up on you as VFP goes looking for a field named Caption in the first work area. Of course, single-letter variable and table names are a lousy idea anyway (most of the time—we're still fond of variables like x, y, z, and o for quick and dirty testing), so the workaround for this isn't terribly painful. It's like the old joke—"Doctor, it hurts when I do this."—"Then don't do that." Use names longer than one character and you'll never run into this problem.
Why Won't You Validate Me?
Here's a behavior that drove people nuts in FoxPro 2.x and, even though the whole context surrounding it has changed in Visual FoxPro, it continues to drive people nuts. Say your user is entering a new record and is sitting on a field that requires validation. After entering bad data for that field, but before moving focus to another field, the user clicks the Save button on your toolbar or chooses Save from the menu. Whoosh—the data is saved, including the bad data. What happened?In VFP, as in FoxPro 2.x, the Valid routine for a text field doesn't execute until focus leaves that field. Clicking a button on a toolbar or picking a menu item doesn't change focus and therefore doesn't fire the Valid method or the LostFocus method, of course. (In fact, a toolbar never has focus, which lets you do pretty cool things.)Why does it behave this way? Because we want it to. It feels wrong in this situation, but suppose the toolbar or menu item the user chose was Select All or Paste. We sure wouldn't want the focus to change (and the Valid and LostFocus methods to fire) in that case. So how do we make sure the data gets validated? Simple—make sure focus changes. One way to do this is to reset focus to the same field:_SCREEN.ActiveForm.ActiveControl.SetFocus()Since menus and toolbars don't get the focus, _SCREEN.ActiveForm is still the same form as before. We just set the focus back to the object that had it, which triggers that control's Valid, LostFocus, When and GotFocus methods.
You Want To Print That Where?
Letting users choose the printer for a report at runtime and having it automatically adjust itself for that printer's settings ought to be a piece of cake. Isn't that one of the things Windows is supposed to handle for us? Unfortunately, VFP tries to be too smart and ends up making things a lot harder than they need to be.When you create a report with the Report Designer, information about the currently selected printer and its settings is stored in the first record of the report table (FRX). When you print the report, VFP checks that information and uses it. If the selected printer was the Windows default, VFP is smart enough to use whatever printer the user chose. But if the selected printer was something else, VFP assumes that you meant it when you created the report with that printer chosen, and it expects to print to that printer. Why does it behave this way? Well, we think the developers were trying to be helpful. They figured that, if you'd gone to the trouble of configuring a printer especially for the report, they ought to pay attention. The problem with this is that the people using your application probably don't even have the same printer you do. The other problem is that this is such a non-intuitive way of arranging for special settings that we can't imagine anyone doing it on purpose.So how do you get VFP to print to the user's chosen printer and honor that printer's settings? Easy—throw out the stored settings. The information is in the Tag, Tag2 and Expr fields of the first record of the report. Just blank 'em out. Our friend Brad Schulz, who knows more about printing from FoxPro than anyone else, suggests making a copy of the report at runtime, blanking the Tag, Tag2 and Expr fields of the copy, then stuffing the Expr field (which is plain text in an INI-file type format) with the settings you really want. Then, use the copy to run the report. Another friend, Rick Schummer, is a wiz at application deployment. He uses a ProjectHook for his projects that, when an EXE is built, automatically opens every report in the project and blanks the necessary fields. That way, he doesn't have to worry about forgetting this important step when he's preparing to send the application to his client.But It Ran Okay in VFP 5!
Normally, the folks at Microsoft (and, before them, the folks at Fox Software) go out of their way to make sure that, whatever they change in a new version of FoxPro, code that ran in the old version will still run in the new one. But in VFP 6, they broke that rule. Not only that, they did it on purpose. Say what?!Because the year 2000 was looming, the Fox team figured it was about time to really make FoxPro developers aware of the bugs lurking in their old code. So they added the SET STRICTDATE command to help us find problems and to keep us from making them in the first place. When you turn STRICTDATE on, VFP lets you know if any of your code contains ambiguous dates. Great, that sounds good.But here's the catch. By default, it's set to moderate strictness in the development environment. That means that any date or datetime constants that don't use the long unambiguous format (that is, {^1958-09-01} rather than {9/1/58}, the latter of which could be either January 9 or September 1, depending on what SET DATE is used) cause an error. (See the Reference section for the details.)Well, it's nice that they can find our errors for us, but why they heck didn't they make the old way the default? Because if they had, we'd keep going along in our misguided belief that our old code was Y2K-compliant. They're forcing us to pay attention.About now, you're probably wondering how you're supposed to upgrade your users to newer versions of VFP if all your dates are going to fail. That's easy. By default, STRICTDATE is set to 0 for them (that is, at runtime), but you'll want to set it to 2 on your development machine so you can catch and squash these bugs.But It Ran Okay in VFP 6!
As with VFP 6, some things were changed in VFP 7 that might break code written in earlier versions (although that's much less likely than the changes made in VFP 6).A couple of changes were made to the _DBLCLICK system variable. First, it no longer contains both the interval necessary for two clicks to be considered a double-click and the interval during which keystrokes will perform incremental searching (which seems like a daft combination in hindsight). Starting in VFP 7, the latter interval is contained in the _INCSEEK system variable. Second, rather than the default of 0.5 seconds that previous versions had, _DBLCLICK now defaults to the value set by the user in the Mouse Control Panel applet. That means we can now create applications that are more respectful of the user's wishes (what a concept!). Thus, there's very little reason for you to touch _DBLCLICK in your applications anymore. For lack of a similar system setting for incremental searching, _INCSEEK also defaults to the user's specified double-click setting. We recommend you add this one to the Options dialog of your applications and let the user set it there.Another change is that the Top, Left, Height and Width properties of _VFP and _SCREEN are no longer identical. The properties of _VFP now reflect the entire VFP window, while those of _SCREEN contain the values of the "client" area of the window, the white area of the window that doesn't include the title bar, menu bar, toolbars, status bar, and so forth. This is a Good Thing, since we can now determine how much actual space we have to work in without having to adjust for the size of the title bar, menu bar, toolbars, status bar, and so forth. However, if you have code that subtracts these sizes from the _SCREEN properties, you'll end up with values that are much too small. Be sure to look for any such code and either use _VFP instead of _SCREEN or (a better idea) don't make any adjustments to the values of the _SCREEN properties.The spelling checker included with earlier versions was dropped in VFP 7. Since you couldn't legally distribute it with your applications, the only code this should break is developer tools. If it breaks any client code, you need to check REDIST.TXT in the VFP home directory to see what other files you might be distributing in violation of the VFP license agreement!The CENTRAL, FOXCODE, FOXGEN, FOXGRAPH and FOXVIEW commands were removed in VFP 7. Since these had no place in any application and have been obsolete for years, that shouldn't break any code.