Prefixing names using some notation

Started by
96 comments, last by phresnel 13 years, 11 months ago
Let's say we have this little convention of prefixing variable names, based on the kind of the variable:

prefix - meaning         (sample variable name)

p      - pointer         (pWindow)
c      - class or struct (cBox)
r      - reference       (rNode)
a      - array           (aObjects)
f      - real number     (fTime)
i      - integer         (iIndex)
n      - unsigned integer(nVertices) // usually used for count
What is the disadvantage of using such prefixes versus not using any prefixes for the variable names at all? For example if somewhere in someones code you'd see a cleverly named variable:
data
What can you say about it and how could you continue using it without looking up its declaration or looking around for other code using that same variable? If the variable was prefixed with p, you'd automatically know that it's a pointer, that you can write -> and hope that intellisense will show you a list of its members, and that you may be concerned by its life time (like make sure that it's destroyed somewhere appropriate using delete). If the variable was prefixed with a, you'd be aware that it's an array of some type, also that you may have to delete it using delete[]. If the variable was prefixed with c, you'd know that you may continue writing a . and see what intellisense has to offer, also that you shouldn't be concerned by its life time, since it will be destroyed when it goes out of scope. If the variable was prefixed with r, you'd know mostly the same stuff as if it was prefixed with c, except that you probably shouldn't be attempting to use the variable as a temporary, since you may overwrite some useful data somewhere outside your current scope. Another advantage of prefixing is that for example if you wrote fps = frameCount / ticks * 1000; you can't say for sure if the result in fps will be an integer or a real number (which you may be expecting), unless you know that at least one of variables frameCount or ticks is of real type. Having them prefixed with n, i or f saves you the time of going to see their declarations, or worse - getting only the integer quotient of the division during playtesting, while you may have expected to get a real value. If you happen to be working in a large function with a lot of different variables it's always easier to remember the kind of variable you currently need rather than its name, so you may just type in its prefix and select the variable you need from the intellisense list. While it's been said around the internet that variable names without prefixes are more readable, you're getting less information from its name and you will end up needing to look up the declaration of the variables in order to know what you must do with them which adds time to reading the code, also burdens your thinking by making you explicitly remember what kind each variable is.
Advertisement
On the origins of species... um, Hungarian notation.


The rest of the arguments can be best explained with this code:
// MUST BE 7const int MAX = 4;


Code changes. Hence variable names should reflect the function, not the form. Once a variable is referenced in 500 files, across 20 projects, renaming it simply isn't possible anymore.
The variable isn't that likely to require a change of its kind, especially if it's already so widely spread. And even if it is inevitably needed to change the kind of the variable, it is likely that the name would have to be changed anyway.
Quote:Original post by Giedrius
saves you the time of going to see their declarations,


You mean the 0.2 second mouse-over tool-tip delay? Or the 0.2 second right-click -> go to declaration/definition?

Hungarian notation was useful in the past when IDE functionality was next to non-existent. Nowadays it only hinders development. If you don't believe me, start a project using Hungarian notation. Keep developing it and I guarantee you'll either forget to use Hungarian notation or get tired of it.
It's more likely to take 0.2 seconds when there's a prefix. It still takes more time to roll over your mouse to see the tooltip or go to the declaration using your keyboard. And you may also forget the kind of the variable after a while. Having it in the prefix may give you information at a simple glance.
You shouldn't prefix it with a type meaning, but rather with a usage meaning. For example: it's a data member, its an input / output variable for a function, it's temporary etc...

If you don't know the type, or the kind-of-type, without a prefix, you should seriously consider to refactor the code.
[size="2"]SignatureShuffle: [size="2"]Random signature images on fora
Quote:Original post by Giedrius
The variable isn't that likely to require a change of its kind, especially if it's already so widely spread.


Real world experience says otherwise.

Quote:And even if it is inevitably needed to change the kind of the variable, it is likely that the name would have to be changed anyway.

Which works great for a hobby project.

In practice, there will be multiple projects, each having dozens of branches, features back-ported, released DLLs in use by potentially millions of customers, all referencing same names, needing to support 5 year old files that have passed end of life, ....

API/interface is the single most expensive thing to change. This is why most APIs in heavy use are not updated, but deprecated, while features are always only added, never removed (looking at you Java).

Same goes for WinAPI. Layer upon layer of new concepts, but nothing ever removed.


And another C/C++ gotcha:
int i = (int)pFoo;

pFoo is pointer to foo, pointers are 32 bit, int is 32 bit. Works fine.

Except that Microsoft had to release extra training documents to discuss how all applications had to be patched, since pFoo was no longer same as pFoo, even if used in same application. Some of pFoos were now 64 bit, while others were 32 bit. Some were even 16 bit.


And while this could be fixed via p32Foo and p64Foo, it breaks elsewhere. Pointers need to be natively sized, so naming them p32 and p64 doesn't make sense - they will be whatever platform they are built on.

wchar_t - how many bytes? wstrlen expects wchar_t, yet size of wchar_t is up to compiler, so p2bwct (pointer to 2 byte wchar_t) isn't compatible with p4bwct (pointer to 4 byte wchar_t).


Hungarian notation has been proven as a falacy. The article linked before discusses on why the wrong one got adopted.
I use pVar for pointers and mVar for members. I'll also sometimes use oVar to signify "out" parameters to functions.

Other than that I think prefixes are pretty useless. Even the ones I use are mostly out of habit rather than practical necessity.
Quote:Original post by Decrius
If you don't know the type, or the kind-of-type, without a prefix, you should seriously consider to refactor the code.

For example if you'd have a variable named "diffuseTexture", there's no way to change its name so that you may know without looking at its declaration whether it's a pointer, an object, a reference, or maybe an enum or something else.

I personally find it easier to read or write code if I have such information available without having to explicitly look it up.


So the main reason for not using these prefixes is that some extremely widespread variable might need its type changed?
Quote:Original post by Giedrius
For example if you'd have a variable named "diffuseTexture", there's no way to change its name so that you may know without looking at its declaration whether it's a pointer, an object, a reference, or maybe an enum or something else.


Why does it matter? If it's just about the . vs ->, VAX will actively fix your typos [grin]

The reason your argument is invalid is because you never end up in some random function, with some random variable that you have absolutely no preexisting knowledge about, and actually having to use that variable. If you are using the variable, then you will already know its type, and, if not, the mouse-over tool-tip will tell you.

This topic is closed to new replies.

Advertisement