Logo

Hacker’s Guide to Visual FoxPro
An irreverent look at how Visual FoxPro really works. Tells you the inside scoop on every command, function, property, event and method of Visual FoxPro.

Local, Private, Public

These three commands let you specify the scope of variables. FoxPro has had PRIVATE and PUBLIC for a long time, but LOCAL was added in Visual FoxPro. In the words of an ad, this changes everything. Visual FoxPro 7 adds other features we’ve been looking for: early binding and strong typing. So what’s the big deal about early binding? We can define a variable as a class, and, during development, IntelliSense reads the type library and displays properties and methods. Cool. Way cool.

Usage

LOCAL [ ARRAY ] Variable1 [ AS cType [ OF cClassLib ] ] ;
      [ , Variable2 [ , ... ] ]
PUBLIC [ ARRAY ] Variable1 [ AS cType [ OF cClassLib ] ] ;
       [ , Variable2 [ , ... ] ]
PRIVATE Variable1 [ , Variable2 [ , ... ] ]
PRIVATE ALL [ LIKE FileSkel | EXCEPT FileSkel ]

Parameter

Value

Meaning

cType

Character

The data type. This can be a FoxPro data type, such as String, Double, or Logical. It can also be any VFP base class, such as Form or Spinner. You can also pass your own class, in which case you should use the cClassLib parameter so VFP can find your class. (You can register your classes with the IntelliSense manager; then you don't need to include cClassLib.) You may also use any class name found in the Registry, such as "Excel.Application" or "Word.Application".

 cClassLib

Character

If cType is a class name defined in a class library, the name of the class library.

In addition to the distinction between the three scopes (discussed below), there’s a big difference between what LOCAL and PUBLIC do and what PRIVATE does. LOCAL and PUBLIC actually create variables—once you issue them, the variables actually exist, and early binding can take place. PRIVATE doesn’t create variables—it reserves names—so if and when you create the variable, it becomes private. This difference has been tripping people up for years.

VFP 7 has a new application property: LanguageOptions. When set to 1, you must declare all memory variables PUBLIC or LOCAL before using them, else a DEBUGOUT message occurs. Because PRIVATE only reserves names, any attempts to use a variable declared PRIVATE triggers an error if LanguageOptions is 1. See LanguageOptions in the Reference section for more information.

Though the syntax diagram above doesn’t show it, to declare local or public arrays, whether or not you include the ARRAY keyword, you need to specify the array dimensions.

Okay, on to scope. We’ll start with PUBLIC because it’s easy. If you make a variable public, it can be seen in any routine at all. It continues to exist until you explicitly RELEASE it. You can hide a public variable by declaring a private or local variable of the same name.

All variables you create in the Command Window are public.

You can’t make an existing variable public. If you try, you’ll get an error message. You have to release the variable first, then declare it public.

Except when working in the Command Window, there’s very little reason ever to create a public variable anymore. Public variables are dangerous—they’re hard to keep track of and are more likely to cause problems in your applications than any others.

There are better ways of making a value available globally. If a login name needs to be accessed and used throughout an application, rather than declaring it public (and available for any program to manipulate, fold, spindle and mutilate), consider crafting a “Security” or “Application” object whose protected properties contain these previously global variables. Use custom methods within this object to return the values when they’re needed. Though it seems like a lot of work to set up, this technique can make it easier in the long run to extend the functionality of your application, and a lot less likely that some new routine will come along and clobber your variable’s value.

PRIVATE is a little tricky. Private variables are visible in the routine where you create them and in all routines called by that routine, unless those routines have their own private or local variables with the same names. When the routine that created the variable finishes executing, it’s automatically released. (You can, of course, release it yourself first.)

Got that? We didn’t think so. Think of it this way: When you create a private variable, you can see it until the routine that created it ends (or you explicitly release it). If that routine calls another routine, it too can see your variable unless it declares a variable of its own with the same name.

Because no routine should have to know what variables are used by the routine that called it (or the one that called that one or the one that called that one), in FoxPro 2.x, good programmers began every routine with a PRIVATE declaration for every variable they intended to use or a PRIVATE ALL LIKE something, which reserved a set of variable names for the routine. This protected the variables of the calling routine. Otherwise, a variable used but not declared explicitly in a routine could clobber the value of the same-named variable in a routine higher in the calling chain.

Fortunately, there’s a better way. Local variables can be seen only in the routine that creates them. It doesn’t matter what else you call—nothing outside the one routine can see a local variable.

Local is the way to go. Pretend you’re working in Pascal and declare every variable right up front (or right before you use it). Use LOCAL every time unless you have a very specific reason not to. Then, document that reason. If a subroutine needs to know the value of a variable in your calling routine, pass it explicitly as a parameter. This good programming practice is referred to as “loose coupling,” and results in better documented, easier to maintain code.

Example

PUBLIC cUserName    && But don't really do this
PRIVATE ALL LIKE j* && Variables beginning with j are private
LOCAL nCnt, cName

The strong typing and early binding features merit some additional discussion. FoxPro is a weakly typed language, meaning that a variable can store any data type, even changing data types throughout the application. Strong typing means the variable is declared as a specific type, such as a character data type or a particular class, and it doesn’t change throughout the life of the variable. In VFP 7, FoxPro doesn’t enforce the strong typing, so you can declare a variable as character, then immediately set it to a numeric value. Strong typing, along with the Session class, really shines when creating COM servers (see “It was Automation, You Know” in “Wow, What a Concept!”). So if you’re not writing COM servers, why would you use strong typing that doesn’t? To document your code, of course.

Closely related to strong typing is early binding. If you define a variable as a class, while you are writing code, IntelliSense goes out and reads the class definitions (or the type library), and presents you with the properties and methods of the class you’re coding against. Not only does this nearly eliminate typos, it also exposes properties and methods that you might not otherwise have seen. Early binding is particularly near and dear to the Office Automation specialists among the authors, as they make it much easier to write code for the Office servers. No more trying to remember complex object hierarchies.

Example

LOCAL cMyString AS Character && Use this to document your code.
LOCAL oMyForm AS FORM
LOCAL oExcel AS "Excel.Application"

See Also

Dimension, External, LanguageOptions, Parameters, Session