Coding standards and naming conventions are topics that are treated religiously rather than objectively. However, most people (including myself) find them very useful. Naming conventions are supposed to make source code easier to read, easier to maintain and easier to debug.
I do not intend to re-specify all the details of standards such as Hungarian Notation. Instead I'll focus on conventions concerned with object technology.
The notations I present here are based on standards used by Microsoft as well as many other companies, including Flash Creative Management. Yair Alan Griver described similar standards in his Visual FoxPro 3.0 Codebook. The wide acceptance of these standards is one of their great strengths. Nevertheless, programmers can still alter these standards to make them match their own needs. I added a couple of variations to these standards that serve my needs very well. Regardless, one of the advantages of standards is the fact that everybody knows them. Altered standards that seem to have some advantages might not work that well after all, since they can cause major confusion that outweighs all the gained advantages.
I'd like to discuss the original standards suggested by Microsoft and Flash Creative Management, as well as some of my own variations. You can decide for yourself whether or not these variations make sense or if you feel it's smarter to stick with the original version.
The original conventions suggest that all objects have to be named according to a single scheme. This scheme is based on notations used in other languages like Visual Basic. It suggests that every object name should have a three-letter prefix that specifies the base class.
It seems that very few people actually stick to this convention; they differentiate between two different groups of object names instead. One uses the three-letter prefix while the other one is more along the lines of variable naming conventions that I'll discuss in a moment.
Contained objects
Contained objects have a clearly defined ownership—they belong to the objects that contain them. Often, these objects are composed using instance programming and pseudo-subclassing. Usually, they are created during design time (early composition), using drag and drop in the class designer. Sometimes they are assembled at runtime (late composition), usually due to some implementation issues like using classes that can't be modified in the Visual Class Designer. Contained objects are always members of other objects and cannot exist by themselves.
This is the kind of object name that uses the three-letter prefix to indicate the base class. The prefix is always lowercase, while the actual name begins with an uppercase character. The name doesn't contain underscores. If the name is a composition of multiple words, each word starts with an uppercase character. Here is a list of all prefixes used for object bases on FoxPro classes:
FoxPro class |
Prefix |
Example |
ActiveDocument |
acd |
acdInvoiceApplet |
CheckBox |
chk |
chkItemIsActive |
Column (Grid-Column) |
col or grc |
colCustomerName |
ComboBox |
cbo or cmb |
cobLanguagecmbCustomerGroup |
CommandButton |
cmd |
cmdApply |
Container |
cnt |
cntCustomerInfo |
Control |
ctl |
ctlAddressField |
Custom |
cus |
cusBehavior |
EditBox |
edt or txt |
EdtMemo |
Form |
frm, doc or dlg |
frmCustomer |
FormSet |
frs |
frsPayroll |
Grid |
grd |
grdLineItems |
Header (Grid-Header) |
grh or hea |
grhCaption |
Hyperlink |
hyp or lnk |
hypEMailAddress |
Image |
img or pic |
imgWizard |
Label |
lbl |
lblName |
Line |
lin |
linHorizontal |
ListBox |
lst |
lstStyles |
OLEControl (ActiveX Control) |
ole or acx |
oleTreeView |
OLEBoundControl |
ole or olb |
oleQuickTime |
OptionButton |
opt |
optYes |
OptionGroup |
ogr or opg |
ogrOutput |
Page |
pag |
pagStep1 |
PageFrame |
pgf |
pgfWizard |
ProjectHook |
pjh |
pjhVisualWebBuilderProject |
Separator |
sep |
sepDocument |
Shape |
shp |
shpRectangle |
Spinner |
spn |
spnPercentage |
TextBox |
txt |
txtName |
Timer |
tmr |
tmrObserver |
Toolbar |
tbr |
tbrNavigation |
Keep in mind that these conventions are meant to be helpful, not a burden. For this reason, some of the prefixes aren't used very often. ProjectHooks, for instance, are usually used at design time only. Unless you are creating a tool you want to give away, you probably won't want to bother with these conventions. Some objects like the separator simply don't do a whole lot; for this reason, many people don't even go through the hassle of defining a name. That's fine.
The only personal variation I added is the txt prefix for edit boxes. Even though this prefix is already used for regular text boxes, I found that I often end up replacing edit boxes with text boxes or vice versa. The special naming convention for the edit boxes became a major hassle because I had to go through all my code and replace the name. After all, edit boxes are just specialized text boxes that allow longer text.
Stand-alone objects
The second group of objects are stand-alone objects. Most of the contained objects are used for the user interface. For this reason, there are more stand-alone objects than contained ones. Stand-alone objects are created using CreateObject() or NewObject() functions rather than by .AddObject() or .NewObject() methods. Typically, the ownership of these objects is not clearly defined. An object can create a reference to an existing object and keep it alive even though the previous owner has already released it.
Naming of stand-alone objects is very similar to naming variables. They have a scope and a type, which is always "o." Keep in mind that references to stand-alone objects are just variables. The other issues attached to stand-alone objects are discussed in the "Variable naming conventions" section.
Names for stand-alone objects are always chosen in source code, just as you define variable names.
Just as we have naming conventions for objects, we also have conventions for the classes they are based on. Unlike the conventions for object naming, these conventions are simple and straightforward. Typically, classes have a lowercase, one-letter prefix indicating whether a class is concrete or abstract.
Class type |
Prefix |
Example |
Abstract |
a |
aDialog |
Concrete |
c |
cPrintDialog |
Originally, people used "c" to indicate a class. This doesn't make a whole lot of sense, though, because classes can be easily identified as such. Therefore, no special indication is needed. Whether a class is abstract or concrete is valuable information. There is no other simple way to specify that a class is abstract, which makes this simple naming convention a powerful and elegant solution.
This topic is not entirely related to object-oriented technology, but since object references are just variables with fancy names, I have a good excuse to discuss variable naming conventions as well.
Variables typically have a two-letter lowercase prefix that indicates their scope and type. Each word of the actual name starts with an uppercase letter. No underscores are used.
Scope |
Prefix |
Example |
Public (Global) |
<none> or g |
gcUserName |
Private |
p |
pcHTMLOutput |
Local |
l |
lcLine |
Parameter |
t, p or l |
tcItemId |
Property (Attribute) |
<none> or a |
Customer.cName |
The scope is quite straightforward. One of my variations is to use an "l" or "p" for parameters instead of the "t". I don't think the "t" adds a whole lot, but it hides the actual scope. In Visual FoxPro, parameters can be private or local. It wasn't like that in FoxPro 2.x since there were no local variables. However, the "t" is a dinosaur brought over from the old days and it takes away the information that "l" or "p" provides.
Object references are treated a little differently than regular variables. Whenever they are public (global), the notation doesn't require a scope, so you'll see oApp, but not goApp. Why? Well, I don't know, but it doesn't seem to hurt anything since global object references are the only variables that don't have a scope.
Another special case is properties. Their scope is automatically determined by the object they belong to. Some people add an "a" for "attribute" (that's what C++ people call properties). I don't have a problem with that, but I don't see a real advantage either. Others use an "s" for "static," because properties fulfill the requirements for a static variable, at least when it comes to object lifetime and visibility. I don't agree with that, since this is only true when the property is protected; a property is not just a regular variable after all. Also, there is no such a thing as a "static property." FoxPro doesn't support that, but I still try to avoid the confusion—who knows what new features Visual FoxPro 7.0 will have? The same is true for real static variables. I do like the idea of adding the visibility to the property names, though. This has saved me many times from trying to access a property that was protected and therefore not visible. The following table demonstrates these prefixes:
Scope |
Prefix |
Example |
Public (Global) |
g |
THISFORMSET.gnToolbars |
Protected |
p |
THIS.pcUserName |
Hidden |
h |
THIS.hcPassword |
The following is a list of all variable types used in Visual FoxPro:
Type |
Prefix |
Example |
Array |
a |
laItems(1,1) |
Character |
c |
GcUserName |
Collection |
a or e |
laForms(1,1) |
Currency |
y |
lyPrice |
Date |
d |
LdLastModified |
DateTime |
t |
ltTimestamp |
Double |
b |
pbValue |
Float |
f |
lfTotal |
General |
g |
lgVideo |
Integer |
i |
liCounter |
Logical |
l |
llActive |
Memo |
m |
pmComments |
Numeric |
n |
lnLineNumber |
Object |
o |
oApplication |
Variant |
v |
lvReturnValue |
These variables are pretty straightforward. The only one that requires some extra explanation is the collection. Collections are either treated like regular arrays, or they use the letter "e". I guess this was the only letter of the word "collection" that wasn't taken by another variable type. I don't see a real advantage to using the "e" instead of the simpler and more intuitive "a". Array collections aren't real collections anyway, so it doesn't really matter.
There is no special naming convention for table fields. It's obvious that fields can't really have a scope, since they're always visible throughout the current data session. Indicating the scope in the field name would be pointless. Not quite as obvious is the reason for dropping the field type. Let's discuss that in a little more detail.
One reason for adding the type to variables is the fact that FoxPro treats all variables as "semi-variants." Variables do have a certain type, but you can change that type simply by assigning a new value. This is powerful, but also dangerous. The naming convention makes it obvious if somebody assigns a value of the wrong type to a variable.
Fields, on the other hand, aren't variants. Therefore, the danger of assigning an invalid value isn't as great; and even if it happens, you'll get an error message right away. This helps to avoid hard-to-find bugs and anomalies, and the naming convention isn't really necessary.
One might argue that the field type is still a helpful hint, especially when scattering data to objects, and I have to agree. But hey! Nobody says you can't add the type in your field names if you want to.
For some mystical reason, nobody so far has come up with naming conventions for methods. There would be some good reasons to do so. Methods have return values of certain types. They also request a specific number of parameters—some by value and others by reference. We have to figure out all these issues by ourselves. However, I have to admit that it would be pretty weird to pack all this information into a naming convention, but adding the visibility and the return type couldn't hurt.
The following tables show some suggestions:
Scope |
Prefix |
Example |
Public (Global) |
g or none |
THISFORMSET.glRefreshToolbars() |
Protected |
p |
THIS.pcGetName() |
Hidden |
h |
THIS.hlValidatePassword() |
The return type of a method is very similar to its variable type. However, there are some differences in the details, mostly because not every field type can be a return type as well.
Return Type |
Prefix |
Example |
Character |
c |
THIS.gcGetUserName() |
Currency |
y |
THIS.pyGetPrice() |
Date |
d |
THIS.hdGetLastModifiedDate() |
DateTime |
t |
oApplication,gtGetTimestamp() |
Logical |
l |
loInvoice.plIsActive() |
Memo |
m or c |
THIS.pmGetComments() |
None |
x or none |
loMail.SendMail |
Numeric |
n |
THIS.gnGetCurrentLineNumber() |
Object |
o |
goDataService.gpGetRecord() |
Variant |
v |
THISFORM.txtPhone.gvGetNumber() |
Methods that are visible throughout an application and don't have a return value are about as close as you can get to defining your own commands in Visual FoxPro. Whenever I create a method that does something I'd really like to see as a native Visual FoxPro command, I don't add any prefixes to it.
A note about parentheses: I don't add them, because I don't think using them with methods adds a whole lot. The danger of confusing methods and properties is minimal, especially when using proper naming conventions. The only scenario where methods could be confused with properties is when they are used to assign a value to another variable or property, as in the following example:
lcCaption = THISFORM.Caption
lcCaption = THISFORM.GetCaption()
The first line refers to a property and the second one calls a method. In this case, the parentheses are required anyway. In all the other scenarios, it's obvious whether the code represents a property or a method.
Keep in mind that this is not part of the original conventions. However, I don't see a good reason to use naming conventions for properties and variables but not for methods.
There are a number of other conventions that we haven't discussed. Some are concerned with coding style, others with table naming, and so on. Other conventions take an approach that's quite different from the Hungarian Notation I discussed in this chapter.
This book is not the place to discuss all of these. Other people have done an outstanding job doing that, so I decided to stick to the topic and talk about object-oriented programming instead.
Advantages and disadvantages of naming conventions
As mentioned above, the question of whether one wants to use naming conventions or not is rather religious and hardly ever objective. As a believer, I'm in danger of treating the topic the same way, but I'll still try to look at the downsides from an objective point of view.
One concern with using naming conventions is that one might lose the advantage of alphabetically sorted lists. Properties that have a prefix will not show up sorted correctly in property sheets and in the Class Browser. I don't see a major problem with that, especially since user-defined properties are always at the bottom of the list anyway, and therefore aren't sorted properly. I guess everyone has to decide for himself whether this is a disadvantage or not. If it bothers him, I have to grant him a point.
Another concern is the readability of source code. My opinion is that prefixes don't affect readability very much. It might take a little time to get used to it, but then it shouldn't be an issue anymore. The information you can get out of the prefix should outweigh the disadvantages by far. But again: If one doesn't like it, I couldn't argue with him. After all, this is all based on personal opinion.
As with most techniques described in this book, the advantages don't come for free if you just blindly follow the guidelines. The actual naming of variables, properties and methods is at least equally important as following the actual notation. The variable name "lnX", for instance, is a lot worse than using "Counter", even though the latter doesn't follow the naming convention. The obvious solution would be to use "lnCounter", which combines the standard with an intuitive name.
Other examples are even more obvious. Using "lnLine" and "lcLine" is a good one. I use these often, especially when iterating through lines of a memo field.
Sometimes, a name that seems to be intuitive is not as obvious as it first seems. Let's consider "Number," for instance. How could we know if "TelephoneNumber" is numeric or alphanumeric? What about "CustomerNumber"? Using "lcTelephoneNumber" and "lnCustomerNumber" instead clarifies the situation.
Hungarian Notation also makes debugging a lot easier. If you treat properties and memvars as if they were not variants and all of a sudden "lnCount" is character, you have valuable information about what's gone wrong.
Naming conventions in interfaces
Naming conventions should not be used in programming interfaces provided for other programmers. Imagine using a third-party class library that uses a naming convention you are not familiar with. This could end up being a major disaster, since you start mixing different conventions and therefore lose the advantages of either one. It's far better to use a component that doesn't use any conventions at all. In this case you lose the advantage of conventions in that component, but it doesn't hurt your own conventions. If not having the convention is a problem for you, you could always create a wrapper that uses your conventions.
Take the Visual FoxPro base classes, for example. None of them follows Hungarian Notation, even though Microsoft promotes that idea in the Visual FoxPro documentation. Keep in mind that all those conventions are just suggestions. Forcing someone to use a notation he doesn't like does more damage than good.