This could have been banner-node.jpg
February 2007
18
From Joshua

Hungarian Notionan

Hungarian Notation

Charles Simonyi
Microsoft Corporation
Reprinted November 1999
MSDN Online Library, http://msdn.microsoft.com/library/techart/hunganotat.htm

Program Identifier Naming Conventions

This monograph is intended to give you the flavor of the major ideas behind the conventions.

When confronted with the need for a new name in a program, a good programmer will generally consider the following factors to reach a decision:

  1. Mnemonic value—so that the programmer can remember the name.

  2. Suggestive value—so that others can read the code.

  3. “Consistency”—this is often viewed as an aesthetic idea, yet it also has to do with the information efficiency of the program text. Roughly speaking, we want similar names for similar quantities.

  4. Speed of the decision—we cannot spend too much time pondering the name of a single quantity, nor is there time for typing and editing extremely long variable names.

All in all, name selection can be a frustrating and time consuming subtask. Often, a name that satisfies some of the above criteria will contradict the others. Maintaining consistency can be especially difficult.

Advantages of the Conventions

The following naming conventions provide a very convenient framework for generating names that satisfy the above criteria. The basic idea is to name all quantities by their types. This simple statement requires considerable elaboration. (What is meant by “types”? What happens if “types” are not unique?) However, once we can agree on the framework, the benefits readily follow. The following are examples:

  1. The names will be mnemonic in a very specific sense: If someone remembers the type of a quantity or how it is constructed from other types, the name will be readily apparent.

  2. The names will be suggestive as well: We will be able to map any name into the type of the quantity, hence obtaining information about the shape and the use of the quantity.

  3. The names will be consistent because they will have been produced by the same rules.

  4. The decision on the name will be mechanical, thus speedy.

  5. Expressions in the program can be subjected to consistency checks that are very similar to the “dimension” checks in physics.

Type Calculus

As suggested above, the concept of “type” in this context is determined by the set of operations that can be applied to a quantity. The test for type equivalence is simple: could the same set of operations be meaningfully applied to the quantities in questions? If so, the types are thought to be the same. If there are operations that apply to a quantity in exclusion of others, the type of the quantity is different.

The concept of “operation” is considered quite generally here; “being the subscript of array A” or “being the second parameter of procedure Position” are operations on quantity x (and A or Position as well). The point is that “integers” x and y are not of the same type if Position (x,y) is legal but Position (y,x) is nonsensical. Here we can also sense how the concepts of type and name merge: x is so named because it is an x-coordinate, and it seems that its type is also an x-coordinate. Most programmers probably would have named such a quantity x. In this instance, the conventions merely codify and clarify what has been widespread programming practice.

Note that the above definition of type (which, incidentally, is suggested by languages such as SIMULA and Smalltalk) is a superset of the more common definition, which takes only the quantity’s representation into account. Naturally, if the representations of x and y are different, there will exist some operations that could be applied to x but not y, or the reverse.

Let us not forget that we are talking about conventions that are to be used by humans for the benefit of humans. Capabilities or restrictions of the programming environment are not at issue here. The exact determination of what constitutes a “type” is not critical, either. If a quantity is incorrectly classified, we have a style problem, not a bug.

Naming Rules

My thesis discusses in detail the following specific naming rules:

  1. Quantities are named by their type possibly followed by a qualifier. A convenient (and legal) punctuation is recommended to separate the type and qualifier part of a name. (In C, we use a capital initial for the qualifier as in rowFirst: row is the type; First is the qualifier.)

  2. Qualifiers distinguish quantities that are of the same type and that exist within the same naming context. Note that contexts may include the whole system, a block, a procedure, or a data structure (for fields), depending on the programming environment. If one of the “standard qualifiers” is applicable, it should be used. Otherwise, the programmer can choose the qualifier. The choice should be simple to make, because the qualifier needs to be unique only within the type and within the scope—a set that is expected to be small in most cases. In rare instances more than one qualifier may appear in a name. Standard qualifiers and their associated semantics are listed below. An example is worthwhile: rowLast is a type row value; that is, the last element in an interval. The definition of Last states that the interval is “closed”; that is, a loop through the interval should include rowLast as its last value.

  3. Simple types are named by short tags that are chosen by the programmer. The recommendation that the tags be small is startling to many programmers. The essential reason for short tags is to make the implementation of rule 4 realistic. Other reasons are listed below.

  4. Names of constructed types should be constructed from the names of the constituent types. A number of standard schemes for constructing pointer, array, and different types exist. Other constructions may be defined as required. For example, the prefix p is used to construct pointers. prowLast is then the name of a particular pointer to a row type value that defines the end of a closed interval. The standard type constructions are also listed below.

In principle, the conventions can be enriched by new type construction schemes. However, the standard constructions have proved to be sufficient in years of use. It is worth noting that the types for data structures are generally not constructed from the tags of their fields. First of all, constructions with over two components would be unwieldy. More important, the invariant property of data structure, the set of operations in which the constructions participate, seems to be largely independent of the fields of the structure that determine only the representation. We all have had numerous experiences with changes in data structures that left the operations (but not the implementation of the operations) unchanged. Consequently, I recommend the use of a new tag for every new data structure. The tag with some punctuation (upper case initial or all upper case) should also be used as the structure name in the program. New tags should also be used if the constructions accumulate to the point where readability suffers.

In my experience, tags are more difficult to choose than qualifiers. When a new tag is needed, the first impulse is to use a short, descriptive, common, and generic English term as the type name. This is almost always a mistake. One should not preempt the most useful English phrases for the provincial purposes of any given version of a given program. Chances are that the same generic term could be equally applicable to many more types in the same program. How will we know which is the one with the pretty “logical” name, and which have the more arbitrary variants typically obtained by omitting various vowels or by other disfigurement? Also, in communicating with the programmer, how do we distinguish the generic use of the common term from the reserved technical usage? By inflection? In the long run, an acronym that is not an English word may work out the best for tags. Related types may then share some of the letters of the acronym. In speech, the acronym may be spelled out, or a pronounceable nickname may be used. When hearing the special names, the informed listener will know that the special technical meaning should be understood. Generic terms should remain free for generic use.

For example, a color graphics program may have a set of internal values that denote colors. What should one call the manifest value for the color red? The obvious choice (which is “wrong” here) is RED. The problem with RED is that it does not identify its type. Is it a label or a procedure that turns objects RED? Even if we know that it is a constant (because it is spelled all caps, for example), there might be several color-related types. Of which one is RED an instance? If I see a procedure defined as paint (color), may I call it with RED as an argument? Has the word RED been used for any other purpose within the program? So we decide to find a tag for the color type and use the word Red as a qualifier.

Note that the obvious choice for the qualifier is in fact that the “correct” one! This is because the use of qualifiers are not hampered by any of the above difficulties. Qualifiers are not “exclusive” (or rather they are exclusive only within a smaller set), so we essentially need not take into account the possibility of other uses of the term Red. The technical use of the term will be clear to everyone when the qualifier is paired with an obviously technical type tag. Since qualifiers (usually) do not participate in type construction, there is no inherent reason why they would need to be especially short.

Conversely, the tag for the type of the color value should not be “color.” Just consider all the other color-related types that may appear in the graphics program (or in a future variant): hardware encoding of color, color map entry number, absolute pointer to color map entry, color values in alternate color mapping mode, hue-brightness-saturation triples, other color values in external interfaces; printers, plotters, interacting external software, and so on. Furthermore, the tag will have to appear in names with constructed types and qualifiers.

A typical arbitrary choice could be co (pronounced see-oh). Or, if co was already taken, cv, cl, kl, and so on. Note that the mnemonic value of the tags is just about average: not too bad, but not too good either. The conventions cannot help with creating names that are inherently mnemonic. Instead, they identify, compress, and contain those parts of the program that are truly individual, thus arbitrary. The lack of inherent meaning should be compensated by ample comments whenever a new tag is introduced. This is a reasonable suggestion because the number of basic tags remains very small, even in a large system.

In conclusion, the name of our quantity would be coRed, provided that the color type co is properly documented. The value of the name will show later in program segments such as the following:

      if co == coRed then *mpcopx[coRed]+=dx …

At a glance we can see that the variable co is compared with a quantity of its own kind; coRed is also used as a subscript to an array whose domain is of the correct type. Furthermore, as we will see, the color is mapped into a pointer to x, which is de-referenced (by the *operator in this example) to yield an x type value, which is then incremented by a “delta x” type value. Such “dimensional analysis” does not guarantee that the program is completely free from bugs, but it does help to eliminate the most common kinds. It also lends a certain rhythm to the writing of the code: “Let’s see, I have a co in hand and I need an x; do I have a mpcox? No, but there is a mpcopx that will give me a px; *px will get me the x…”

Naming for “Writability”

A good yardstick for choosing a name is to try to imagine that there is an extraordinary reward for two programmers if they can independently come up with the same program text for the same problem. Both programmers know the reward, but cannot otherwise communicate. Such an experiment would be futile, of course, for any sizable problem, but it is a neat goal. The reward of real life is that a program written by someone else, which is identical to what one’s own program would have been, is extremely readable and modifiable. By the proper use of the conventions, the idea can be approached very closely, give or take a relatively few tags and possibly some qualifiers. The leverage of the tags is enormous. If they are communicated, are agreed on beforehand, or come from a common source, the goal becomes reachable and the reward may be reaped. This makes the documentation of the tags all the more important.

An example of such a consideration is the discretionary use of qualifiers in small scopes where a quantity’s type is likely to be unique, for example in small procedures with a few parameters and locals or in data structures which typically have only a few fields. One might prefer to attach a qualifier even to a quantity with a unique type of “writability,” the ability for someone else to come up with the name without hesitation. As many textbooks point out, the “someone else” can be the same programmer sometime in the future revisiting the long-forgotten code.

Conclusion   Do not use qualifiers when not needed, even if they seem valuable.

Naming Rules for Procedures

Unfortunately, the simple notion of qualified typed tags does not work well for procedure names. Some procedures do not take parameters or do not return values. The scopes of procedure names tend to be large. The following set of special rules for procedures has worked quite satisfactorily:

  1. Distinguish procedure names from other names by punctuation, for example by always starting with a capital letter (typed tags of other quantities are in lower case). This alleviates the problem caused by the large scope.

  2. Start the name with the tag of the value that is returned, if any.

  3. Express the action of the procedure in one or two words, typically transitive verbs. The words should be punctuated for easy parsing by the reader (a common legal method of punctuation is the use of capital initials for every word).

  4. Append the list of tags of some or all of the formal parameters if it seems appropriate to do so.

The last point is contrary to the earlier remarks on data structure naming. When the parameters to a procedure are changed, typically all uses of the procedure will need to be updated. There is an opportunity during the update to change the name as well. In fact, the name change can serve as a useful check that all occurrences have been found. With data structures, the addition or change of a field will not have an effect on all uses of the changed structure type. Typically, if a procedure has only one or two parameters, the inclusion of the parameter tags will really simplify the choice of procedure name.

Table 1. Some examples for procedure names

Name Description
InitSy Takes an sy as its argument and initializes it.
OpenFn fn is the argument. The procedure will “open” the fn. No value is returned.
FcFromBnRn Returns the fc corresponding to the bn,rn pair given. (The names cannot tell us what the types sy, fn, fc, and so on, are.)

The following is a list of standard type constructions. (X and Y stand for arbitrary tags. According to standard punctuation, the actual tags are lowercase.)

Table 2. Standard type constructions

pX Pointer to X.
dX Difference between two instances of type X. X + dX is of type X.
cX Count of instances of type X.
mpXY An array of Ys indexed by X. Read as “map from X to Y.”
rgX An array of Xs. Read as “range X.” The indices of the array are called:
iX
index of the array rgX.
dnX (rare) An array indexed by type X. The elements of the array are called:
eX
(rare) Element of the array dnX.
grpX A group of Xs stored one after another in storage. Used when the X elements are of variable size and standard array indexing would not apply. Elements of the group must be referenced by means other then direct indexing. A storage allocation zone, for example, is a grp of blocks.
bX Relative offset to a type X. This is used for field displacements in a data structure with variable size fields. The offset may be given in terms of bytes or words, depending on the base pointer from which the offset is measured.
cbX Size of instances of X in bytes.
cwX Size of instances of X in words.

Where it matters, quantities named mp, rg, dn, or grp are actually pointers to the structures described above.

One obvious problem with the constructions is that they make the parsing of the types ambiguous. Is pfc a tag of its own or is it a pointer to an fc? Such questions can be answered only if one is familiar with the specific tags that are used in a program.

The following are standard qualifiers. (The letter X stands for any type tag. Actual type tags are in lowercase.)

Table 3. Standard qualifiers

XFirst The first element in an ordered set (interval) of X values.
XLast The last element in an ordered set of X values. XLast is the upper limit of a closed interval, hence the loop continuation condition should be: X <= XLast.
XLim The strict upper limit of an ordered set of X values. Loop continuation should be: X < XLim.
XMax Strict upper limit for all X values (excepting Max, Mac, and Nil) for all other X: X < XMax. If X values start with X=0, XMax is equal to the number of different X values. The allocated length of a dnx vector, for example, will be typically XMax.
XMac The current (as opposed to constant or allocated) upper limit for all X values. If X values start with 0, XMac is the current number of X values. To iterate through a dnx array, for example:
for x=0 step 1 to xMac-1 do … dnx[x] …
or
for ix=0 step 1 to ixMac-1 do … rgx[ix] …
XNil A distinguished Nil value of type X. The value may or may not be 0 or -1.
XT Temporary X. An easy way to qualify the second quantity of a given type in a scope.

Table 4. Some common primitive types

f Flag (Boolean, logical). If qualifier is used, it should describe the true state of the flag. Exception: the constants fTrue and fFalse.
w Word with arbitrary contents.
ch Character, usually in ASCII text.
b Byte, not necessarily holding a coded character, more akin to w. Distinguished from the b constructor by the capital letter of the qualifier in immediately following.
sz Pointer to first character of a zero terminated string.
st Pointer to a string. First byte is the count of characters cch.
h pp (in heap).

The following partial example of an actual symbol table routine illustrates the use of the conventions in a “real life” situation. The purpose of this example is not to make any claims about the code itself, but to show how the conventions can help us learn about the code. In fact, some of the names in this routine are standard.

1   #include “sy.h”
2   extern int *rgwDic;
3   extern int bsyMac;
4   struct SY *PsySz(char sz[])
6      {
7      char *pch;
8      int cch;
9      struct SY *psy, *PsyCreate();
10      int *pbsy;
11      int cwSz;
12      unsigned wHash=0;
13      pch=sz;
14      while (*pch!=0
15         wHash=(wHash<>11+*pch++;
16      cch=pch-sz;
17      pbsy=&rgbsyHash[(wHash&077777)%cwHash];
18      for (; *pbsy!=0; pbsy = &psy->bsyNext)
19         {
20         char *szSy;
21         szSy= (psy=(struct SY*)&rgwDic[*pbsy])->sz;
22         pch=sz;

23         while (*pch==*szSy++)
24            {
25            if (*pch++==0)
26               return (psy);
27            }
28         }
29      cwSz=0;
30      if (cch>=2)
31         cwSz=(cch-2/sizeof(int)+1;
32      *pbsy=(int *)(psy=PsyCreate(cwSY+cwSz))-rgwDic;
33      Zero((int *)psy,cwSY);
34      bltbyte(sz, psy->sz, cch+1);
35      return(psy);
36      }

The tag SY is the only product specific type in this routine. The definition of SY is found in the include file sy.h (fair enough). The type name itself is in all capitals, a common convention.

Line 2—says that there is an array of words, which is called Dic(tionary). Remember that since Dic is a qualifier, it is named traditionally.

Line 3—is the offset pointing beyond the last sy (see b constructor + Mac standard qualifier.) One has to guess at this time that this is used for allocating new sy’s. The “base” of the offset would also have to be guessed to be rgwDic. Actually, the name grpsy would have been better instead of rgwDic, from this local perspective. In the real program, the rgwDic area is used for a number of different purposes, hence the “neutral” name.

Line 4—is a procedure declaration. Procedure returns a pointer to an SY as the result. The parameter must be a zero-terminated string.

Lines 7-12—declare quantities. The usages should be clear from the names. For example, cwSz is the number of words in some string (probably the argument), pbsy is a pointer to an offset of an sy (p constructor + b constructor). The only qualifier used here is in wHash—the hash code.

Line 13pch will be a pointer to the first character of sz.

Line 16cch is the count of characters (c constructor) ostensibly, in sz.

Line 17cwHash is the number of words in the hash table (I would have called it ibsyMax). In a way, the qualifier on rgbsyHash could be omitted, but it helps identify the hash table in external contexts.

Lines 17-18—note the opportunities for dimensional checking:

      pbsy = &rgbsy[…] follows from pX = &rgX[…]
      pbsy =  &psy->bsyNext follows from pX=&pY->X; or pX = &Y.X
      

So even the use of -> instead of . follows from local context. The p on the left hand side signals the need for the & on the right.

Line 20—introduces a new sz, qualified to distinguish it from the argument. The qualifier, very appropriately, is the source of the datum, Sy.

Line 23—given the use of szSy in this line, the name pchSy would have been a little more appropriate. No harm done, however.

Lines 29-31—this strange code has to do with the fact that the declaration of SY includes 2 bytes of sz, so that cwSz is really the number of words in the sz-2 bytes! This should deserve a comment or at least a qualifier M2 (minus 2) or the like. cwSY is the length of the SY structure in words. The all caps qualifier is not strictly standard, but it helps to associate the quantity with the declaration of SY, rather than with any random sy instance.

PsyCreate is a good procedure name; PsyCreateCw would have been even better. In line 32 we can also see an example of dimensional checking: While we have a psy inside the parenthesis, we need a bsy for the left side (*pbsy=bsy!) so we subtract the “base” of the bsy from the psy.

bX + base = pX; hence: bX = pX - base.

In closing, it is evident that the conventions participated in making the code more correct, easier to write, and easier to read. Naming conventions cannot guarantee good code, however; only the skill of the programmer can.

Object Hungarian Notation Naming Conventions for VB

From Microsoft KB Article Q173738
Object                             Prefix                Example
—————————————————————————————————————
Form                               frm                   frmFileOpen
Check box                          chk                   ReadOnly
Combo box                          cbo                   cboEnglish
Data-bound combo box               dbc                   dbcEnglish
Command button                     cmd                   cmdCancel
Data                               dat                   datBiblio
Directory list box                 dir                   dirSource
Drive list box                     drv                   drvTarget
File list box                      fil                   filSource
Frame                              fra                   fraLanguage
Grid                               grd                   grdPrices
Data-bound grid                    dbg                   dbgPrices
Horizontal scroll bar              hsb                   hsbVolume
Image                              img                   imgIcon
Label                              lbl                   lblHelpMessage
Line                               lin                   linVertical
List box                            lst                  lstPolicyCodes
Data-bound list box                dbl                   dblPolicyCode
Menu                               mnu                   mnuFileOpen
OLE container                      ole                   oleObject1
Option button                      opt                   optFrench
Picture box                        pic                   picDiskSpace
Shape                              shp                   shpCircle
Text box                           txt                   txtGetText
Timer                              tmr                   tmrAlarm

Object                             Prefix                Example
————————————————————————————————————
Vertical scroll bar                vsb                   vsbRate
Animation button                   ani                   aniMailBox
bed      Pen                       Bedit                 bedFirstName
Checkbox                           chk                   chkReadOnly
Picture clip                       clp                   clpToolbar
Communications                     com                   comFax
Control                            ctl                   ctrCurrent
Data control                       dat                   datBiblioDirectory
Directory list box                 dir                   dirSource
Common dialog ctrl                 dlg                   dlgFileOpen
Drive list box                     drv                   drvTarget
File list box                      fil                   filSource
Form                               frm                   frmEntry
Frame (3d)                         fra                   fraStyle
Gauge                              gau                   gauStatus
Group push button                  gpb                   gpbChannel
Graph                              gra                   graRevenue
Grid                               grd                   grdPrices
Pen Hedit                          hed                   hedSignature
Horizontalscrollbar                hsb                   hsbVolume
Image                              img                   imgIcon
Pen Ink                            ink                   inkMap
Keyboard key status                key                   keyCaps
Label                              lbl                   lblHelpMessage
Line                               lin                   linVertical
MDI child form                     mdi                   mdiNote
MAPI message                       mpm                   mpmSentMessage
MAPI session                       mps                   mpsSession
MCI                                mci                   mciVideo
Menu                               mnu                   mnuFileOpen
Object                             obj                   objUserTable
Option Button (3d)                 opt                   optRed
Outline control                    out                   outOrgChart
3d Panel                           pnl (3d)              pnlTitleList
Report control                     rpt                   rptQtr1Earnings
Shape controls                     shp                   shpCircle
Spin control                       spn                   spnPages
Timer                              tmr                   tmrAlarm
Vertical scroll bar                vsb                   vsbRate

Database Objects                   Prefix                Example
—————————————————————————————————————
ODBC Database                      db                    dbAccounts
ODBC Dynaset object                dyn                   dynSalesByRegion
Field collection                   fld                   fldCustomer
Field object                       fld                   fldAddress
Form                               frm                   frmNewUser
Index object                       idx                   idxAge
Index collection                   idx                   idxNewAge
Macro                              mcr                   mcrCollectUsers
QueryDef object                    qry                   qrySalesByRegion
Query                              qry                   qrySalesByRegion
Report                             rpt                   rptAnnualSales
Snapshot object                    snp                   snpForecast
Table object                       tbl                   tblCustomer
TableDef object                    tbd                   tbdCustomers

The following table lists standard third-party vendor name prefix characters to be used with control prefixes:
Vendor                         Abbreviation
—————————————————————-
MicroHelp (VBTools)            m
Pioneer Software Q+E Database  p
Crescent Software              c
Sheridan Software              s
Other (miscellaneous)          o

Objects                            Prefix                Example
——————————————————————————————————-
Alarm(Microhelp)                   almm                  almmAlarm
Animate(Microhelp)                 anim                  animAnimate
Callback(Microhelp)                calm                  callback
Combo Box(Pioneer)                 cbop                  cbopComboBox
Combo Box(Sheridan)                cbos                  cbosComboBox
DB_Check(Pioneer)                  chkp                  chkpCheckBox
chart(Microhelp)                   tm                    tmChart
Clock(Microhelp)                   clkm                  clkmClock
Command Button(Microhelp)          cmdm                  cmdmCommandButton
DB_Command(Pioneer)                cmdp                  cmdpCommandButton
Command Button(Group)(Microhelp)   cmgm                  cmgmBtton
Command Button (icon) (Microhelp)  cmim                  cmimCommandButton
CardDeck(Microhelp)                crdm                  crdmCard
Dice(Microhelp)                    dicm                  dicmDice
SSDir(Sheridan)                    dirs                  dirsDirList
SSDrive(Sheridan)                  drvs                  drvsDriveList
File List(Microhelp)               film                  filmFileList
SSFile(Sheridan)                   fils                  filsFileList
Flip(Microhelp)                    flpm                  flpmButton
Form Scroll(Microhelp)             fsrm                  fsrmFormScroll
Gauge(Microhelp)                   gagm                  gagmGauge
Graph(Other)                       gpho                  gphoGraph
Q_Grid(Pioneer)                    grdp                  grdpGrid
Horizontal Scroll Bar(Microhelp)   hsbm                   hsbmScroll
DB_Hscroll(Pioneer)                hsbp                   hsbpScroll
Histo(Microhelp)                   hstm                   hstmHistograph
Invisible(Microhelp)               invm                   invmInvisible
Icon Tag(Microhelp)                itgm                   itgmListBox
Key State(Microhelp                kstm                   kstmKeyState
Label (3d) (Microhelp)             lblm                   lblmLabel
Line(Microhelp)                    linm                   linmLine
DB_List(Pioneer)                   lstp                   lstpListBox
SSList(Sheridan)                   lsts                   lstsListBox
MDI Control(Microhelp)             mdcm                   mdcmMDIChild
SSMenu(Sheridan)                   mnus                   mnusMenu
Marque(Microhelp)                  mrqm                   mrqmMarque
OddPic(Microhelp)                  odpm                   odpmPicture
Picture(Microhelp)                 picm                   picmPicture
DB_Picture(Pioneer)                picp                   picpPicture
Property Vwr(Microhelp)            pvrm                   vrmPropertyViewer
DB_RadioGroup(Group)(Pioneer)      radp                   radqRadioGroup
Slider(Microhelp)                  sldm                   sldmSlider
Spinner(Microhelp)                 spnm                   spnmSpinner
Spreadsheet(Microhelp)             sprm                   sprmSpreadsheet
Stretcher(Microhelp)               strm                   strmStretcher
Screen Saver(Microhelp)            svrm                   svrmSaver
Switcher(Microhelp)                swtm                   swtmSwitcher
Tag(Microhelp)                     tagm                   tagmListBox
Timer(Microhelp)                   tmrm                   tmrmTimer
ToolBar(Microhelp)                 tolm                   tolmToolBar
Tree(Microhelp)                    trem                   tremTree
Input(Microhelp) (Text)            txtm                   inpmText
DB_Text(Microhelp)                 txtp                   txtpText
Vertical Scroll Bar(Microhelp)     vsbm                   vsbmScroll
DB_VScroll(Pioneer)                vsbp                   vsbpScroll

From Win98 Developers Handbook

Using Hungarian notation, variable names begin with one or more lowercase letters that denote the variable type, thus providing an inherent identification. For example, the prefix h is used to identify a handle, as in hWnd or hDlg, referring to window and dialog box handles, respectively. In like fashion, the prefix lpsz identifies a long pointer to a null-terminated (ASCIIZ) string. Table 2.1 summarizes the Hungarian notation conventions.

Table 2.1: Hungarian Notation Conventions

Prefix Data type
b Boolean
by byte or unsigned char
c Char
cx / cy short used as size
dw DWORD, double word or unsigned long
fn Function
h Handle
i int (integer)
l Long
n short int
p a pointer variable containing the address of a variable
s string
sz ASCIIZ null-terminated string
w WORD unsigned int
x, y short used as coordinates

More VB stuff

From Microsoft KB article Q110264

Object Naming Conventions for Standard Objects

The following tables define the MCS standard object name prefixes. These prefixes are consistent with those documented in the Visual Basic Programmers Guide.
Prefix    Object Type                           Example
———————————————————————————-
ani       Animation button                      aniMailBox
bed       Pen Bedit                             bedFirstName
cbo       Combo box and drop down list box      cboEnglish
chk       Checkbox                              chkReadOnly
clp       Picture clip                          clpToolbar
cmd (3d)  Command button (3D)                   cmdOk (cmd3dOk)
com       Communications                        comFax
ctr       Control (when specific type unknown)  ctrCurrent
dat       Data control                          datBiblio
dir       Directory list box                    dirSource
dlg       Common dialog control                 dlgFileOpen
drv       Drive list box                        drvTarget
fil       File list box                         filSource
frm       Form                                  frmEntry
fra (3d)  Frame (3d)                            fraStyle (fra3dStyle)
gau       Gauge                                 gauStatus
gpb       Group push button                     gpbChannel
gra       Graph                                 graRevenue
grd       Grid                                  grdPrices
hed       Pen Hedit                             hedSignature
hsb       Horizontal scroll bar                 hsbVolume
img       Image                                 imgIcon
ink       Pen Ink                               inkMap
key       Keyboard key status                   keyCaps
lbl       Label                                 lblHelpMessage
lin       Line                                  linVertical
lst       List box                              lstPolicyCodes
mdi       MDI child form                        mdiNote
mpm       MAPI message                          mpmSentMessage
mps       MAPI session                          mpsSession
mci       MCI                                   mciVideo
mnu       Menu                                  mnuFileOpen
opt (3d)  Option Button (3d)                    optRed (opt3dRed)
ole       OLE control                           oleWorksheet
out       Outline control                       outOrgChart
pic       Picture                               picVGA
pnl3d     3d Panel                              pnl3d
rpt       Report control                        rptQtr1Earnings
shp       Shape controls                        shpCircle
spn       Spin control                          spnPages
txt       Text Box                              txtLastName
tmr       Timer                                 tmrAlarm
vsb       Vertical scroll bar                   vsbRate 

Object Naming Convention for Database Objects

Prefix        Object Type          Example
—————————————————————
db            ODBC Database        dbAccounts
ds            ODBC Dynaset object  dsSalesByRegion
fdc           Field collection     fdcCustomer
fd            Field object         fdAddress
ix            Index object         ixAge
ixc           Index collection     ixcNewAge
qd            QueryDef object      qdSalesByRegion
qry (suffix)  Query (see NOTE)     SalesByRegionQry
ss            Snapshot object      ssForecast
tb            Table object         tbCustomer
td            TableDef object      tdCustomers
 
NOTE: Using a suffix for queries allows each query to be sorted with its associated table in Microsoft Access dialogs (Add Table, List Tables Snapshot).

Menu Naming Conventions

Applications frequently use an abundance of menu controls. As a result, you need a different set of naming conventions for these controls. Menu control prefixes should be extended beyond the initial mnu label by adding an additional prefix for each level of nesting, with the final menu caption at the end of the name string. For example:
Menu Caption Sequence   Menu Handler Name
Help.Contents           mnuHelpContents
File.Open               mnuFileOpen
Format.Character        mnuFormatCharacter
File.Send.Fax           mnuFileSendFax
File.Send.Email         mnuFileSendEmail 
When this convention is used, all members of a particular menu group are listed next to each other in the object drop-down list boxes (in the code window and property window). In addition, the menu control names clearly document the menu items to which they are attached.

Naming Conventions for Other Controls

For new controls not listed above, try to come up with a unique three character prefix. However, it is more important to be clear than to stick to three characters.

For derivative controls, such as an enhanced list box, extend the prefixes above so that there is no confusion over which control is really being used. A lower-case abbreviation for the manufacturer would also typically be added to the prefix. For example, a control instance created from the Visual Basic Professional 3D frame could uses a prefix of fra3d to avoid confusion over which control is really being used. A command button from MicroHelp could use cmdm to differentiate it from the standard command button (cmd).

Third-party Controls

Each third-party control used in an application should be listed in the application’s overview comment section, providing the prefix used for the control, the full name of the control, and the name of the software vendor:
Prefix    Control Type        Vendor
cmdm      Command Button      MicroHelp 

Variable and Routine Naming

Variable and function names have the following structure: <prefix><body><qualifier><suffix>
Part          Description                                  Example
—————————————————————————————————————
<prefix>      Describes the use and scope of the variable. iGetRecordNext

<body>        Describes the variable.                      iGetNameFirst
<qualifier>   Denotes a derivative of the variable.        iGetNameLast
<suffix>      The optional Visual Basic type character.    iGetRecordNext% 
Prefixes:

The following tables define variable and function name prefixes that are based on Hungarian C notation for Windows. These prefixes should be used with all variables and function names. Use of old Basic suffixes (such as %, &, #, etc.) are discouraged.

Variable and Function Name Prefixes:
Prefix    Converged    Variable Use         Data Type  Suffix
—————————————————————————————————————
b         bln          Boolean              Integer    %
c         cur          Currency - 64 bits   Currency   @
d         dbl          Double - 64 bit      Double     #
                       signed quantity
dt        dat          Date and Time        Variant
e         err          Error
f         sng          Float/Single - 32    Single     !
                       bit signed
                       floating point
h                      Handle               Integer    %
i                      Index                Integer    %
l         lng          Long - 32 bit        Long       &
                       signed quantity
n         int          Number/Counter       Integer    %
s         str          String               String     $
u                      Unsigned - 16 bit    Long       &

                       unsigned quantity
          udt          User-defined type
vnt       vnt          Variant              Variant
a                      Array 
NOTE: the values in the Converged column represent efforts to pull together the naming standards for Visual Basic, Visual Basic for Applications, and Access Basic. It is likely that these prefixes will become Microsoft standards at some point in the near future.

Scope and Usage Prefixes:
Prefix         Description
g              Global
m              Local to module or form
st             Static variable
(no prefix)    Non-static variable, prefix local to procedure
v              Variable passed by value (local to a routine)
r              Variable passed by reference (local to a routine) 
Hungarian notation is as valuable in Visual Basic as it is in C. Although the Visual Basic type suffixes do indicate a variable’s data type, they do not explain what a variable or function is used for, or how it can be accessed. Here are some examples:
iSend - Represents a count of the number of messages sent
bSend - A Boolean flag defining the success of the last Send operation
hSend - A Handle to the Comm interface
Each of these variable names tell a programmer something very different. This information is lost when the variable name is reduced to Send%. Scope prefixes such as g and m also help reduce the problem of name contention especially in multi-developer projects.

Hungarian notation is also widely used by Windows C programmers and constantly referenced in Microsoft product documentation and in industry programming books. Additionally, the bond between C programmers and programmers who use Visual Basic will become much stronger as the Visual C++ development system gains momentum. This transition will result in many Visual Basic programmers moving to C for the first time and many programmers moving frequently back and forth between both environments.

The Body of Variable and Routine Names

The body of a variable or routine name should use mixed case and should be as long as necessary to describe its purpose. In addition, function names should begin with a verb, such as InitNameArray or CloseDialog.

For frequently used or long terms, standard abbreviations are recommended to help keep name lengths reasonable. In general, variable names greater than 32 characters can be difficult to read on VGA displays.

When using abbreviations, make sure they are consistent throughout the entire application. Randomly switching between Cnt and Count within a project will lead to unnecessary confusion.

Qualifiers on Variable and Routine Names

Related variables and routines are often used to manage and manipulate a common object. In these cases, use standard qualifiers to label the derivative variables and routines. Although putting the qualifier after the body of the name might seem a little awkward (as in sGetNameFirst, sGetNameLast instead of sGetFirstName, sGetLastName), this practice will help order these names together in the Visual Basic editor routine lists, making the logic and structure of the application easier to understand. The following table defines common qualifiers and their standard meaning:
Qualifier  Description (follows Body)
—————————————————————————————————————
First      First element of a set.
Last       Last element of a set.
Next       Next element in a set.
Prev       Previous element in a set.
Cur        Current element in a set.
Min        Minimum value in a set.
Max        Maximum value in a set.
Save       Used to preserve another variable that must be reset later.
Tmp        A “scratch” variable whose scope is highly localized within the
           code. The value of a Tmp variable is usually only valid across
           a set of contiguous statements within a single procedure.
Src        Source. Frequently used in comparison and transfer routines.
Dst        Destination. Often used in conjunction with Source. 

User Defined Types

Declare user defined types in all caps with _TYPE appended to the end of the symbol name. For example:
Type CUSTOMER_TYPE
      sName As String
      sState As String * 2
      lID as Long
   End Type 
When declaring an instance variable of a user defined type, add a prefix to the variable name to reference the type. For example:
   Dim custNew as CUSTOMER_TYPE 

Naming Constants

The body of constant names should be UPPER_CASE with underscores (_) between words. Although standard Visual Basic constants do not include Hungarian information, prefixes like i, s, g, and m can be very useful in understanding the value and scope of a constant. For constant names, follow the same rules as variables. For Example:
<mnUSER_LIST_MAX   ’ Max entry limit for User list (integer value,
                     ’ local to module)
   gsNEW_LINE        ’ New Line character string (global to entire
                     ’ application) 

Variant Data Type

If you know that a variable will always store data of a particular type, Visual Basic can handle that data more efficiently if you declare a variable of that type.

However, the variant data type can be extremely useful when working with databases, messages, DDE, or OLE. Many databases allow NULL as a valid value for a field. Your code needs to distinguish between NULL, 0 (zero), and “” (empty string). Many times, these types of operations can use a generic service routine that does not need to know the type of data it receives to process or pass on the data. For example:
   Sub ConvertNulls(rvntOrg As Variant, rvntSub As Variant)
      ’ If rvntOrg = Null, replace the Null with rvntSub
      If IsNull(rvntOrg) Then rvntOrg = rvntSub
   End Sub 
The are some drawbacks, however, to using variants. Code statements that use variants can sometimes be ambiguous to the programmer. For example:
   vnt1 = “10.01” : vnt2 = 11 : vnt3 = “11” : vnt4 = “x4”
   vntResult = vnt1 + vnt2  ’ Does vntResult = 21.01 or 10.0111?
   vntResult = vnt2 + vnt1  ’ Does vntResult = 21.01 or 1110.01?
   vntResult = vnt1 + vnt3  ’ Does vntResult = 21.01 or 10.0111?
   vntResult = vnt3 + vnt1  ’ Does vntResult = 21.01 or 1110.01?
   vntResult = vnt2 + vnt4  ’ Does vntResult = 11x4 or ERROR?
   vntResult = vnt3 + vnt4  ’ Does vntResult = 11x4 or ERROR? 
The above examples would be much less ambiguous and easier to read, debug, and maintain if the Visual Basic type conversion routines were used instead. For Example:
   iVar1 = 5 + val(sVar2)   ’ use this (explicit conversion)
   vntVar1 = 5 + vntVar2    ’ not this (implicit conversion) 

Commenting Your Code

All procedures and functions should begin with a brief comment describing the functional characteristics of the routine (what it does). This description should not describe the implementation details (how it does it) because these often change over time, resulting in unnecessary comment maintenance work, or worse yet, erroneous comments. The code itself and any necessary in-line or local comments will describe the implementation.

Parameters passed to a routine should be described when their functions are not obvious and when the routine expects the parameters to be in a specific range. Function return values and global variables that are changed by the routine (especially through reference parameters) must also be described at the beginning of each routine.

Routine header comment blocks should look like this (see the next section “Formatting Your Code” for an example):
Section    Comment Description
—————————————————————————————————————
Purpose    What the routine does (not how).
Inputs     Each non-obvious parameter on a separate line with
           in-line comments
Assumes    List of each non-obvious external variable, control, open file,
           and so on.
Returns    Explanation of value returned for functions.
Effects    List of each effected external variable, control, file, and
           so on and the affect it has (only if this is not obvious) 
Every non-trivial variable declaration should include an in-line comment describing the use of the variable being declared.

Variables, controls, and routines should be named clearly enough that in- line commenting is only needed for complex or non-intuitive implementation details.

An overview description of the application, enumerating primary data objects, routines, algorithms, dialogs, database and file system dependencies, and so on should be included at the start of the .BAS module that contains the project’s Visual Basic generic constant declarations.

NOTE: The Project window inherently describes the list of files in a project, so this overview section only needs to provide information on the most important files and modules, or the files the Project window doesn’t list, such as initialization (.INI) or database files.

Formatting Your Code

Because many programmers still use VGA displays, screen real estate must be conserved as much as possible, while still allowing code formatting to reflect logic structure and nesting.

Standard, tab-based, block nesting indentations should be two to four spaces. More than four spaces is unnecessary and can cause statements to be hidden or accidentally truncated. Less than two spaces does not sufficiently show logic nesting. In the Microsoft Knowledge Base, we use a three-space indent. Use the Environment Options dialog to set the default tab width.

The functional overview comment of a routine should be indented one space. The highest level statements that follow the overview comment should be indented one tab, with each nested block indented an additional tab. For example:
**************************************************************************
‘Purpose:   Locate first occurrence of a specified user in UserList array.
‘Inputs:    rasUserList():  the list of users to be searched
’           rsTargetUser:   the name of the user to search for
‘Returns:   the index of the first occurrence of the rsTargetUser
’           in the rasUserList array. If target user not found, return -1.
‘**************************************************************************

‘VB3Line: Enter the following lines as one line
Function iFindUser (rasUserList() As String, rsTargetUser as String) _
   As Integer
   Dim i As Integer           ’ loop counter
   Dim bFound As Integer      ’ target found flag
   iFindUser = -1
   i = 0
   While i <= Ubound(rasUserList) and Not bFound
      If rasUserList(i) = rsTargetUser Then
         bFound = True
         iFindUser = i
      End If
   Wend
End Function 
Variables and non-generic constants should be grouped by function rather than by being split off into isolated areas or special files. Visual Basic generic constants such as HOURGLASS should be grouped in a single module (VB_STD.BAS) to keep them separate from application-specific declarations.

Operators

Always use an ampersand (&) when concatenating strings, and use the plus sign (+) when working with numerical values. Using a plus sign (+) with non-numerical values, may cause problems when operating on two variants. For example:
   vntVar1 = “10.01”
   vntVar2 = 11
   vntResult = vntVar1 + vntVar2         ’ vntResult =  21.01
   vntResult = vntVar1 & vntVar2         ’ vntResult = 10.0111 

Scope

Variables should always be defined with the smallest scope possible. Global variables can create enormously complex state machines and make the logic of an application extremely difficult to understand. Global variables also make the reuse and maintenance of your code much more difficult. Variables in Visual Basic can have the following scope:
Scope             Variable Declared In:            Visibility
—————————————————————————————————————
Procedure-level   Event procedure, sub, or         Visible in the
                  function                         procedure in which
                                                   it is declared
Form-level,       Declarations section of a form   Visible in every
Module-level      or code module (.FRM, .BAS)      procedure in the
                                                   form or code
                                                   module
Global            Declarations section of a code   Always visible
                  module (.BAS, using Global
                  keyword) 
In a Visual Basic application, only use global variables when there is no other convenient way to share data between forms. You may want to consider storing information in a control’s Tag property, which can be accessed globally using the form.object.property syntax.

If you must use global variables, it is good practice to declare all of them in a single module and group them by function. Give the module a meaningful name that indicates its purpose, such as GLOBAL.BAS.

With the exception of global variables (which should not be passed), procedures and functions should only operate on objects that are passed to them. Global variables that are used in routines should be identified in the general comment area at the beginning of the routine. In addition, pass arguments to subs and functions using ByVal, unless you explicitly want to change the value of the passed argument.

Write modular code whenever possible. For example, if your application displays a dialog box, put all the controls and code required to perform the dialog’s task in a single form. This helps to keep the application’s code organized into useful components and minimizes its runtime overhead.

Third-party Controls

NOTE: The products discussed below are manufactured by vendors independent of Microsoft. Microsoft makes no warranty, implied or otherwise, regarding these products’ performance or reliability.

The following table lists standard third-party vendor name prefix characters to be used with control prefixes:
Vendor               Abbv
————————————-

MicroHelp (VBTools)  m
Pioneer Software     p
Crescent Software    c
Sheridan Software    s
Other (Misc)         o 
The following table lists standard third-party control prefixes:
Control         Control     Abbr  Vendor     Example            VBX File
Type            Name                                            Name
—————————————————————————————————————
Alarm           Alarm       almm  MicroHelp  almmAlarm          MHTI200.VBX
Animate         Animate     anim  MicroHelp  animAnimate        MHTI200.VBX
Callback        Callback    calm  MicroHelp  calmCallback       MHAD200.VBX
Combo Box       DB_Combo    cbop  Pioneer    cbopComboBox       QEVBDBF.VBX
Combo Box       SSCombo     cbos  Sheridan   cbosComboBox       SS3D2.VBX
Check Box       DB_Check    chkp  Pioneer    chkpCheckBox       QEVBDBF.VBX
Chart           Chart       chtm  MicroHelp  chtmChart          MHGR200.VBX
Clock           Clock       clkm  MicroHelp  clkmClock          MHTI200.VBX
Button          Command     cmdm  MicroHelp  cmdmCommandButton  MHEN200.VBX
                Button
Button          DB_Command  cmdp  Pioneer    cmdpCommandButton  QEVBDBF.VBX
Button (Group)  Command     cmgm  MicroHelp  cmgmBtton          MHGR200.VBX
                Button
                (multiple)
Button          Command     cmim  MicroHelp  cmimCommandButton  MHEN200.VBX
                Button
                (icon)
CardDeck        CardDeck    crdm  MicroHelp  crdmCard           MHGR200.VBX
Dice            Dice        dicm  MicroHelp  dicmDice           MHGR200.VBX
List Box (Dir)  SSDir       dirs  Sheridan   dirsDirList        SS3D2.VBX
List Box (Drv)  SSDrive     drvs  Sheridan   drvsDriveList      SS3D2.VBX
List Box (File) File List   film  MicroHelp  filmFileList       MHEN200.VBX
List Box (File) SSFile      fils  Sheridan   filsFileList       SS3D2.VBX
Flip            Flip        flpm  MicroHelp  flpmButton         MHEN200.VBX
Scroll Bar      Form Scroll fsrm  MicroHelp  fsrmFormScroll     ???
Gauge           Gauge       gagm  MicroHelp  gagmGauge          MHGR200.VBX
Graph           Graph       gpho  Other      gphoGraph          XYGRAPH.VBX
Grid            Q_Grid      grdp  Pioneer    grdpGrid           QEVBDBF.VBX
Scroll Bar      Horizontal  hsbm  MicroHelp  hsbmScroll         MHEN200.VBX
                Scroll Bar
Scroll Bar      DB_HScroll  hsbp  Pioneer    hsbpScroll         QEVBDBF.VBX
Graph           Histo       hstm  MicroHelp  hstmHistograph     MHGR200.VBX
Invisible       Invisible   invm  MicroHelp  invmInvisible      MHGR200.VBX
List Box        Icon Tag    itgm  MicroHelp  itgmListBox        MHAD200.VBX
Key State       Key State   kstm  MicroHelp  kstmKeyState       MHTI200.VBX
Label           Label (3d)  lblm  MicroHelp  lblmLabel          MHEN200.VBX
Line            Line        linm  MicroHelp  linmLine           MHGR200.VBX
List Box        DB_List     lstp  Pioneer    lstpListBox        QEVBDBF.VBX
List Box        SSList      lsts  Sheridan   lstsListBox        SS3D2.VBX
MDI Child       MDI Control mdcm  MicroHelp  mdcmMDIChild       ???
Menu            SSMenu      mnus  Sheridan   mnusMenu           SS3D3.VBX
Marque          Marque      mrqm  MicroHelp  mrqmMarque         MHTI200.VB
Picture         OddPic      odpm  MicroHelp  odpmPicture        MHGR200.VBX
Picture         Picture     picm  MicroHelp  picmPicture        MHGR200.VBX
Picture         DB_Picture  picp  Pioneer    picpPicture        QEVBDBF.VBX
Property Vwr    Property    pvrm  MicroHelp  pvrmPropertyViewer MHPR200.VBX
                Viewer
Option (Group)  DB_RadioGroup radp Pioneer   radqRadioGroup     QEVBDBF.VBX
Slider          Slider      sldm  MicroHelp  sldmSlider         MHGR200.VBX
Button (Spin)   Spinner     spnm  MicroHelp  spnmSpinner        MHEN200.VBX
Spreadsheet     Spreadsheet sprm  MicroHelp  sprmSpreadsheet    MHAD200.VBX
Picture         Stretcher   strm  MicroHelp  strmStretcher      MHAD200.VBX
Screen Saver    Screen Saver svrm MicroHelp  svrmSaver          MHTI200.VBX
Switcher        Switcher    swtm  MicroHelp  swtmSwitcher       ???
List Box        Tag         tagm  MicroHelp  tagmListBox        MHEN200.VBX
Timer           Timer       tmrm  MicroHelp  tmrmTimer          MHTI200.VBX
ToolBar         ToolBar     tolm  MicroHelp  tolmToolBar        MHAD200.VBX
List Box        Tree        trem  MicroHelp  tremTree           MHEN200.VBX
Input Box       Input (Text) txtm MicroHelp  inpmText           MHEN200.VBX
Input Box       DB_Text     txtp  Pioneer    txtpText           QEVBDBF.VBX
Scroll Bar      Vertical    vsbm  MicroHelp  vsbmScroll         MHEN200.VBX
                Scroll Bar
Scroll Bar      DB_VScroll  vsbp  Pioneer    vsbpScroll         QEVBDBF.VBX 

From some unknown web page

a atom
b BOOL (int)
by BYTE (unsigned char)
c char (ANSI ASCII; 8-bit)
cb byte count
cx
cy
int (c is for count; x or y is length)
dw DWORD (unsigned long)
f BOOL; boolean flag
fn function
h HANDLE
hbr HANDLE to a brush
hDC HANDLE to a device context
i int
id integral id value
l LONG (long)
lp long (far) pointer
lpfn long pointer to function
lpsz long pointer to nul-terminated string
n short
np near (short) pointer
p pointer
pfn pointer to function
pst pointer to a structure
psz pointer to a nul-terminated string
pv pointer to void
s string
sz nul (‘\0’) terminated string (string terminated by a zero byte)
u unsigned
v void
w WORD (unsigned 16-bit value; sometimes an unsigned short)
w wide char (UNICODE 16-bit)
x short or int (when used as an X coordinate)
y short or int (when used as a Y coordinate)

Hungarian Notation

First, a little disclaimer:

Please note that this guide is based on MY understanding of Hungarian notation, and may not be completely accurate. Yes, I used to work at Microsoft, but I don’t have the guide we used there anymore. This document has been done almost entirely from memory and is based on how I’ve been writing code for the past few years, so it’s probably actually a bastardized version of the form of Hungarian notation used by Microsoft. There’s a very brief description of Hungarian notation in Charles Petzold’s “Programming Windows”, which I checked with while writing this guide. My intent is to go into much more detail than he does, though.

If you DO know Hungarian, and notice anything wrong with this guide, please send me mail. Thanks.

What is Hungarian notation?

Hungarian Notation is a naming convention that (in theory) allows the programmer to determine, the type and use of an identifier (variable, function, constant, etc.) It is frequently used in Windows programming, so a quick guide (such as this one) may be useful if you’re working with Windows code but don’t know the naming scheme. Note that there is really no such thing as “standard” Hungarian notation (at least as far as I’ve been able to determine). The basic ideas remain the same, however, and the key is to aim for CONSISTENCY.

Variables

Variable names are probably the most common type of identifiers. A variable name in Hungarian notation consists of three parts: the prefix (or constructor), base type (or tag), and qualifier. Not all of these elements will be present in all variable names — the only part that is really needed is the base type.

Base Types (Tags)

The Tag is NOT necessarily one of the types directly provided by the programming language; it may be application-defined (for example, a type dbr might represent a database record structure). Tags are short (usually two or three letters) descriptive reminders about the type of value the variable stores. This type will usually only be useful to someone who knows the application and knows what the basic types the application uses are; for example, a tag co could just as easily refer to a coordinate, or a color. Within a given application, however, the co would always have a specific meaning — all co’s would refer to the same type of object, and all references to that type of object would use the tag co.

Common Tags

These are many basic types that are used in any application. These tags are used for these types.

Tag Description
f Boolean flag. The qualifier should be used to describe the condition that causes the flag to be set (for example, fError might be used to indicate a variable that is set when an error condition exists, and clear when there is no error). The actual data representation may be a a byte, a word, or even a single bit in a bitfield.
ch A single-byte character.
w A machine word (16 bits on Win3.1 X86 machines). This is a somewhat ambiguous tag, and it is often better to use a more specific name. (For example, a word that represents a count of characters is better referred to as a cch than as a w. See the prefixes section for an explanation of the cch notation.)
b A byte (typically 8 bits). See the warnings for w.
l A long integer (typically 32 bits). See the warnings for w.
u An unsigned value. Usually more accurately used as a prefix with one of the integer types described above. For example, a uw is an unsigned word.
r A single-precision real number (float)
d A double-precision real number (double)
bit A single bit. Typically this is used to specify bits within other types; it is usually more appropriate to use f.
v A void. (Rather C-specific, meaning the type is not specified.) This type will probably never be used without the p prefix. This would usually be used for generic subroutines (such as alloc and free) that work with pointers but don’t need to refer to the specific type of data referenced by those pointers.
st A Pascal-type string. That is, the first byte contains the length of the string, and the remainder contains the actual characters in the string.
sz A null-terminated (C-style) string.
fn A function. This will almost always have a p prefix, as about the only useful thing you can do with a function (from a variable’s perspective) is take the address of it.

Prefixes (Constructors)

The base types are not usually sufficient to describe a variable, since variables frequently refer to more complex types. For example, you may have a pointer to a database record, or an array of coordinates, or a count of colors. In Hungarian notation, these extended types are described by the variable’s prefix. The complete type of a variable is given by the combination of the prefix(es) and base type. Yes, it is possible to have more than one prefix — for example, you may have a pointer to an array of database records.

Common Constructors

It is not usually necessary to create a new prefix, although it is certainly possible to do so. The list of standard prefixes should be sufficient for most uses, however.

Constructor Description
p A pointer.
lp A long (far) pointer. (Used on machines with a segmented architecture, such as X86’s under DOS or Win3.1).
hp A huge pointer. (Similar to a far pointer, except that it handles crossing segment boundaries during pointer arithmetic correctly.)
rg An array. An rgch is an array of characters; a pch could point to a specific element in this array. (The notation comes from viewing an array as a mathematical function — the input is the index, and the output is the value at that index. So the entire array is essentially the “range” of that function.)
i An index (into an array). For example, an ich could be used to index into an rgch. I’ve also seen this used for resource IDs under Windows (which makes sense if you think about it — a resource ID is an index into a resource table).
c A count. cch could be the count of characters in the rgch. (As another example, note that the first byte of an st is the cch of that string.)
d The difference between two instances of a type. For example, given a type x used to represent an X-coordinate on a graph, a dx could contain the difference on the X-axis of two such coordinates.
h A handle. Handles are commonly used in Windows programming; they represent resources allocated by the system and handed back to the application. On other systems, a “handle” might be a pointer to a pointer, in which case it might be clearer to use a pp (or lplp if appropriate).
mp A specific type of array, a mapping. This prefix is followed by two types, rather than one. The array represents a mapping function from the first type to the second. For example, mpwErrisz could be a mapping of error codes (wErr) to indexes of message strings (isz).
v A global variable (personally I prefer g for this)

Examples

Tags and constructors are both in lower case, with no seperating punctuation, so some ambiguity is possible if you are not careful in choosing your representations. For example, you probably shouldn’t use pfn to represent a structure you’ve defined, as it could be taken as a pointer (p) to a function (fn). (Even if you ARE careful, some ambiguity is still possible. For example, if you have a handle to a pointer (unlikely, but who knows?), you’d want to represent this as hp, which also means huge pointer. Cases like these should be rare, however, and the true type should still be distinguishable from the context of the code.)

Here are some further examples of constructors + tags:

Variable Description
pch A pointer to a character.
ich An index into an array of characters.
rgsz An array of null-terminated strings (most likely the values stored in the array are actually pointers to the strings, so you could arguably also use rgpsz).
rgrgx A two-dimensional array of x’s. (An array of arrays of x’s.)
pisz A pointer to an index into an array of null-terminated strings. (Or possibly a pointer to a resource ID of a string — the real meaning should be clear within the context of the code.)
lpcw Far pointer to a count of words.

Qualifiers

Although the combination of constructors and tags are enough to specify the type of a variable, it won’t be sufficient to distinguish the variable from others of the same type. This is where the third (optional) part of a variable name, the qualifier, comes in. A qualifier is a short descriptive word or words (or reasonable facsimile) that describes HOW the variable is used. Some kind of punctuation should be used to distinguish the qualifier from the constructor + tag portion. Typically this is done by making the first letter of the qualifier (or of each qualifier if you choose to use more than one word) upper-case.

The use of many variables will fall into the same basic categories, so there are several standard qualifiers:

Qualifier Description
First The first element in a set. This will often be an index or a pointer (for example, pchFirst or iwFirst).
Last The last element in a set. Both First and Last refer to valid values that are in a given set, and are often paired, such as in this sample C loop:
for (iw = iwFirst; iw <= iwLast; iw++)
    {
    …
    }
Min The first element in a set. Similar to First, but Min always refers to the first actual element in a set, while First may be used to indicate the first element actually dealt with (if you’re working with a substring, for example).
Max The upper limit in a set. This is NOT a valid value; xMax is usually equivalent to xLast + 1. The above example loop could also be written as
for (iw = iwFirst; iw < iwMax; iw++)
    {
    …
    }
I’ve also seen Lim used to indicate the limit in much the same manner.
Mac The current upper limit in a set. This is similar to Max, but is used where the upper limit can vary (for example, a variable length structure).
Sav A temporary saved value; usually used when temporarily modifying variables that you want to restore later.
T A temporary variable — one which will be used quickly in a given context and then disposed of or reused.
Src A source. This is usually paired with Dest in copy/transfer operations.
Dest A destination. This is usually paired with Src.

Structures and structure members

Structures are usually by definition their own types, so a given structure usually defines its own tag (for example, the dbr I used earlier in this document).

Structure members should simply be named the same way variables are. Since the context is usually only within the structure itself, name conflicts are less likely, so qualifiers are often not as necessary. If you have multiple instances of a variable type within the structure, you’ll still need the qualifiers, of course (for example, if you’re creating a structure containing name and address string records, you could name them szName and szAddress). If the language does not support seperate contexts for each structure (I think the Microsoft Macro Assembler (MASM) falls into this category, but I haven’t worked with it in a few years), then the structure name is appended to the name of the member as a qualifier. (So the examples given above might be named szNameDbr and szAddressDbr if these fields appeared in the dbr structure.)

Procedures

The simple rules for naming variables don’t always work quite as well for procedures. This is because specifying what the procedure actually does is important, and many procedures won’t have a return value. Also, the context for procedures is usually the entire program, so you have more chance for naming conflicts. To handle these problems, a few modifications are made to the rules:
  1. Procedure names are distinguished from variable names by using some punctuation — for example, function names have the first letter capitalized while variable names begin with lowercase letters.
  2. If the procedure explicitly returns a value (as opposed to implicitly returning one through a variable argument), then the procedure name will begin with the type of value that is returned.
  3. If the procedure is a true function (that is, it operates on its parameters and returns a value with no side-effects), then it is typical to name it XFromYZ…, where X is the type returned and Y, Z, etc., are the types of the parameters. For example, DxFromWnd(hwnd) (or possibly DxFromHwnd(hwnd) if you really want to be specific) could be used for a function that returns the width of a window.
  4. If the procedure has side-effects, then follow the type (if any) with a few words that describe what the procedure does. Each word should be capitalized. For example, FTryMove() could be used to indicate a procedure that checks the validity of a move (in a game, for instance), and returns a boolean value (true/false) to indicate if the move is valid.
  5. If the procedure operates on an object, the type of the object should be appended to the name. For example, InitFoo(pfoo) could indicate a procedure that initializes a structure foo (or more accurately in this case, a structure foo that the procedure is given a pointer to).

Macros and constants

Macros are usually handled the same way as procedures. Constants may be handled as variables (such as fTrue and fFalse), although you’ll often see constants defined in all upper-case (IWFIRST, for example). Some people will use underscores to seperate parts of a constant name if they capitalize them (I_W_FIRST). If I remember correctly, this capitaliztion is NOT really a part of “proper” Hungarian, but I use it myself to distinguish between constants and variables.

Labels

If you need a label for some reason, it can be considered to be a variation on a procedure — labels are effectively identifiers specifying a piece of code. Since labels don’t take parameters or return a value, no types are specified. EndLoop or OutOfMem are typical examples.

Hungarian Notation Reference

Example of an Identifier in Hungarian Notation:
CString* m_ps NameFirst
Prefix Qualifier
What is Hungarian Notation?
Top

Hungarian is a naming convention for identifiers in code, especially, but not exclusively, the C++ and Java languages. Each identifier would have two parts to it, a type and a qualifier.
  • type: the first characters of the identifier specify what type the object is an instance of. This is achieved by adopting part of the name of the type as a prefix on the identifier. The prefix is always entirely lower-case.
  • qualifier: the remainder of the name of the identifier describes what the variable is used for. The qualifier portion can be one word or a run-on word. The qualifier begins with a capital to distinguish it from the type prefix.
Example:
String sNameFirst; //s is a prefix for String type
char cLetter; //c is a prefix for the char type
Button butPushMe; //but is a prefix for the Button type
More explanation about Hungarian notation.

Type Prefixes
Top

Common Type Prefixes

| b | by y | c | C | d | dw | f | g_ | h | I | l | m_ | n | p | s str | sz psz | u | v | w | x | X |
Prefix Meaning Example Notes
p Pointer Finger* pRude; In most cases, p is combined with another prefix; the prefix of the type of object being pointed to. For example:
String* psName
is a pointer to a string object containing a name.
s
str
String String sName;
String strName;
This convention is generally used for first-class string classes.
sz
psz
zero-terminated / null-terminated string char szName[16];
char* pszName;
h Handle HWND hWindow
c Character (char) char cLetter; Sometimes c is used to denote a counter object.
by
y
Byte or Unsigned Char byte byMouthFull;
byte yMouthFull;
n Integer (int) int nSizeOfArray;
f Float float fRootBeer;
d Double double dDecker;
b Boolean boolean bIsTrue;
BOOL bIsTrue;
int bIsTrue;
An integer can store a boolean value as long as you remember not to assign it a value other than 0 or 1
u Unsigned…
w Word or Unsigned Integer unsigned int wValue;
l Long long lIdentifier; Sometimes l is appended to p to denote that the pointer is a long. For example:
lpszName
is a long pointer to a zero-terminated string.
dw Unsigned Long Integer
C
or just a capital first letteri
Class Class CObject;
Class Object;
C is used heavily in Microsoft’s Foundation Classes but using just a capital first letter is emphasized by Microsoft’s J++.
I Interface (ususally a struct or class with only pure virtual methods and no member variables)
class IMotion {
public:
   virtual void Fly() = 0;
};
Used extensively in COM.
X Nested Class
class CRocket {
public:
   class XMotion:public IMotion {
   public:
      void Fly();
   } m_xUnknown;
}
Used extensively in COM.
x Instantiation of a nested class.
class CAirplane {
public:
   class XMotion:public IMotion {
   public:
      void Fly();
   } m_xUnknown;
}
Used extensively in COM.
m_ Class Member Identifiers
class CThing {
private:
   int m_nSize;
};
g_ Global String* g_psBuffer Constant globals are usually in all caps. The g_ would denote that a particular global is not a constant.
v Void (no type) void* pvObject In most cases, v will be included with p because it is a common trick to typecast pointers to void pointers.
Top of table

Type Prefixes for non-common Types

In many cases, you will have identifiers of non-standard types. In this case, it will not do to borrow prefixes from the list of standard prefixes. Instead, the programmer needs to invent his own and, even more importantly, remain consistent with his own notation. To invent a prefix, abreviate the type name in a short and meaningful fashion. If it is not possible to abbreviate and the type name is not too long, you can just use the type name as a prefix.

The Type Prefix will always be entirely lowercase and should reflect the name of the type by abbreviating it distinctively.

Example:
Button buttonPushMe; //this is okay, but awkward
Button butPushMe; //a better abreviation for the type prefix
Button bPushMe; //BAD: can be mistaken for a Boolean
Standard Qualifiers
Top

The Qualifier portion of the identifier can be anything but should accurately and concisely describe the purpose of the object. There is a set of standard qualifiers for variables used in commonly performed programming tasks.

Qualifier Explanation
Sav A temporary from which the value will be restored
Prev A value that follows one behind a current value in an iteration (eg. linked list node pointer)
Cur Current value in some iteration
Next Next value in some iteration
Nil A special illegal value that is distinguished from all legal values. Typically denotes a certain absense of a legal value.
Min Smallest legal index in an array or list. Typically zero.
Max A strict upper limit for legal indexes in an array or list.

Other Hungarian Naming Conventions
Top

Identifiers Containing Multiple Words

If the identifier contains multiple words, then the first letter of each word in the name is capitalized.

Example:
int nThisIsAReallyLongIdentifier

If the identifier contains adjectives that describe the purpose of the object, the adjective succeeds the word it describes.

Example:
CString sNameFirst; //first name
int nNumCowsBrown; //number of brown cows

Functions

Functions should start out with a capital letter and no type prefix. It is not unheard of to start a function with a lowercase letter however. Microsoft urges the use of a capital first letter though the Java awt libraries use a lower-case first letter on member functions.

Example:
CString GetName (); //Microsoft C++ standard
String getName (); //Sun Java standard

Macros and constants

Macros and constants should be entirely in capitals.

Example:
#define MAXSIZE 100
const int MAXSIZE = 100;
More Information About Hungarian Notation
Top

The need for a standard

Programmers typically do not name their identifiers randomly; Programmers commonly name their identifiers mnemonically. However, every programmer is unique and one mnemoic identifier name may mean a lot to one person and nothing to another. A convention is merely a codified style of choosing mnemonics.

One important reason for a standard naming convention is to make your code more easily read by other people. Additional information about an object can be coded into its identifier so that someone reading code does not have to frequently refer back to the objects declaration to find out what type it is. Furthermore, if the identifier relates to what the object is used for in the code, then reading code is greatly simplified because the reader does not have to infer it from how it is used.

Origins of Hungarian notation

Charles Simonya, chief architect at Microsoft is the originator of the Hungarian Notation standard, which is used extensively in Microsoft Windows code. Simonya first used the notation in 1972. The notation was refered to as Hungarian originally as a criticism. At first glance, identifiers using Hungarian Notation appear to be gibberish until the pattern is deduced. Friends of Simonya compared Simonya’s notation convention to some obscure foreign language and since Simonya is Hungarian, that was the obscure foreign language refered to.

Since its inception in 1972, Hungarian Notation has been adopted by Xerox, Apple, 3Com, and of course Microsoft.


Recommended for Delphi

From the Orange County Delphi Users Group Delphi/Pascal Coding Standards http://www.ocdelphi.org/standard.htm

0.2 A Recommended Form of Hungarian Notation for Delphi

Category Item Notation Type Nota-tion Example

Types & classes Exception classes Upper case prefix E ESyntax = class (Exception)
All other types & classes T TEmployee = class (TObject)

Variables, except properties (see note #1) Integer Lower case prefix i iCount: byte;
Small Integer n
Long Integer l
Byte by
Word w
Real (floating point) r rPrice: Real;
Single f
Double d
Extended e
Comp dl
Char c cLetter: Char;
Pascal string or huge string (2.0) s sTitle: String[80];
Null (zero)-terminated string sz szDescription: array[0..1000] of char;
Pointer p pCount: ^iCount;
pChar psz or lpsz pszDescription: pChar;
Boolean b bSallaried: Boolean;
Byte Boolean byb
Word Boolean wb
Long Boolean lb
Date/time dt dtBirthday: TDateTime;

VCL controls Form Lower case prefix frm frmEmployee: TForm;
Label (see note #2) lbl lblStatus: TDBLabel;
(other standard controls) (see chart below) sbtnGo: TSpeedButton;
(subclassed standard controls) (same as base) sbtnGo: TMySpeedButton;
(all other controls, e.g. custom controls for the project at hand) (spell out) linkedimageUSAMap: TlinkedImage;
Persistent database field Delphi-assigned prefix (table or query name) tblEmployeesName: TStringField;

Procedures Procedures, Functions, and Methods (see note #3) No special notation procedure ToggleEmployeeState (Sender: TObject);

Other identifiers constants (typed or untyped) Upper case name with underscores MAX_HEIGHT: Integer = 24;
Enumerated type values Programmer assigned lower case prefix (2-letter code for item type being enumer-ated) TVagueness = (vnBefore, vnAfter, vnOn, vnAbout)
Compiler directive identifiers Upper case name with underscores {$DEFINE QA_MODE}



0.1 Delphi Standard Controls

Palette Group Component Prefix
Standard TButton btn
TCheckBox chk
TComboBox cbo
TEdit edt
TGroupBox grp
TLabel lbl
TListBox lbo
TMainMenu mmnu
TMemo mem
TMenuItem mnu
TPanel pnl
TPopupMenu pmnu
TRadioButton rbtn
TRadioGroup rgrp
TScrollBar sbr
Additional TBevel bvl
TBitBtn bbtn
TDrawGrid dgrd
THeader hdr
TImage img
TMaskEdit medt
TNotebook nbk
TOutline oln
TScrollBox sbo
TShape shp
TSpeedButton sbtn
TStringGrid sgrd
TTabbedNotebook tbnbk
TTabSet tbs
Data Access TBatchMove bmv
TDatabase db
TDataSource ds
TQuery qry
TReport rpt
TStoredProc prc
TTable tab
Data Controls TDBCheckBox dbchk
TDBComboBox dbcbo
TDBEdit dbedt
TDBGrid dbgrd
TDBImage dbimg
TDBListBox dblbo
TDBLookupCombo dblcbo
TDBLookupList dbllbo
TDBMemo dbmem
TDBNavigator dbnav
TDBRadioGroup dbrgrp
TDBText dbtxt
Dialogs TColorDialog dlgcl
TFindDialog dlgfn
TFontDialog dlgft
TOpenDialog dlgop
TPrintDialog dlgpr
TPrinterSetupDialog dlgps
TReplaceDialog dlgrp
TSaveDialog dlgsv
System TDDEClientConv ddecc
TDDEClientItem ddeci
TDDEServerConv ddesc
TDDEServerItem ddesi
TDirectoryListBox dir
TDriveComboBox drv
TFileListBox fil
TFilterComboBox filt
TMediaPlayer mpl
TOLEContainer olec
TPaintBox pbx
TTimer tmr

The Simonyi (Hungarian Notation) Naming Conventions

Microsoft Corporation has substantially adopted a naming convention for its program modules and variables which is sometimes referred to as Hungarian Notation. Charles Simonyi, a Hungarian, developed this method of naming and presented it in his doctoral thesis. He worked for Microsoft and promulgated his theories in the C, Visual Basic, and ACCESS areas of the company.

In this naming convention/style, object names are composed of four parts: 1) prefixes; 2) tag; 3) base name; and, 4) qualifier. Prefixes and tags are always lower-case so the reader’s eyes jump easily to the base name which begins with a uppercase letter. The base name succinctly describes the object, not its class. Object tags are short and mnemonic. Object prefixes provide further information or definition to the object tags and name. Two of the common prefixes are array and index to an array. The index to an array would use the combined prefix of: i and a to denote that iaintPartNum is an index variable to an array of integer Part Numbers. giaintPartNum would be a global index variable to an array of integer Part Numbers. As you can see, a first character of “g” indicates a global variable.

Procedures should be named in the form of VerbNoun. The name should be descriptive of what that procedure does. Remember, a procedure should do one thing only and do it correctly and completely.

The following tags are suggested for the respective variable types: