• Advertisement

Archived

This topic is now archived and is closed to further replies.

Hungarian Notation - no longer necessary?

This topic is 4966 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I didn''t know how old school I was coding until I looked up coding standards on the newer breed of languages (C# and Java). For those who don''t know what that is: http://burks.brighton.ac.uk/burks/foldoc/40/54.htm So... I thought it was good discipline, but it seems that coding standards from both Microsoft and Sun encourage you not to use it. I think that m_ is useful prefix for class variables - esp when reading a hardcopy rather then being assisted by a clever IDE. But I suppose if you prefix "this." before accessing class member variables then thats just as clear. The compiler is likely to optimise out the "this." bit out of the code anyway rather then get a reference to the current object from the current object and then the variable in question. Same argument for s_ for statics I guess - just prepend the class name to make usage clearer. The only thing I can still find to justify is p prefix for pointers (*). This has little meaning or use in C# and Java where you can''t get so muddled with deferencing or pointers to pointers... but in C++ and C I still think a p prefix has a place. Or even a pp for **. Because you REALLY want to know what you are dealing with when it comes to references or pointers - right? And a pointer type is never going to be anything other then a pointer type - it''s not like it''s going to get out of date like if you have iCount... and decide that an integer isn''t big enough so you need to change it to lCount. Thoughts?

Share this post


Link to post
Share on other sites
Advertisement
I used to use a lite version of that notation. After a while, I wondered what the point in using the m_ notation on member variables is if almost EVERYTHING is going to be a member variable. And then I stopped using the notation letters before each variable too.. I considered that it was obvious as it is, but I could always move the mouse cursor over it anyways (which takes less time overall than typing m_i whatever everytime).

Pointers to pointers will cause a compile error if used incorrectly, so don''t need to worry about those. I never use "this" either, unless using overloaded class operators or copy constructors. I always thought that some kind of notation on the parameters for every function would make more since, easy to glance at the code and know what''s going to be affected. But that''s just me, if I code with a group of people then I''ll be happy to accept hungarian style.

Share this post


Link to post
Share on other sites
I think I''m starting to think along the same lines. It''s looking at code without a fancy editor (notepad, vi, whatever) or printed-out that doesn''t have compiler errors thrown up at you that it''s usage could be a bit ambiguous. The only prefix I can justify there is good ol'' p.

Coding in Java and C# - you would not usually come across a situation that used a pointer instead of a reference anyway.

Share this post


Link to post
Share on other sites
I never liked hungarian notation and never used it. Also, when I was beggining with C++, I wasn't working with IDE that would show me the type of the var. And I didn't have any troubles with it. I think, you can guess from the context what type is that var, and if you're coding - you would have to be stupid to use a var without knowing what type and purpose is it (Well - don't know how about others - but I'm not coding blindly - just to guess what is some var for just of its name - I have to look at the comment by the var to see what is it for - and at that time, I can look few pixels to the left and I can see the type of it.).

Also - if you see
if (time >= 1.0) ...   
then it is clear, that 'time' is a double.

Oxyd


"It is better to listen than to speak"
    -- Abba Nisterus


[edited by - Oxyd on June 10, 2004 12:40:09 PM]

[edited by - Oxyd on June 10, 2004 12:41:05 PM]

Share this post


Link to post
Share on other sites
Hungarian notation completely obfuscates code and renders it virtually unmaintainable. The classic example is the fact that you still see LPCSTR ( long pointer to a c string ) scattered throughout the Win32 SDK. Long pointers disappeared along with 16 bit Windows many years ago. Thanks to hungarian notation we now see LPCSTR scattered all over the place even though it is really a non-existant type.

Anyhow, most compilers now a days generally are very informative with type bending errors. Hungarian has absolutely no purpose anymore.

Share this post


Link to post
Share on other sites
Greetings,

Though I am not keen on the complete use of Hungarian notation (particularly of what I see in VC++ 6.0), I do use the following notations which I find useful when using grep to isolate things (like all class members that are pointers)...

class Foobar
{
public:
int m_Value;

public:
int* mp_Value;
};

The use of the "m_" and "mp_" also allow me to clearly disguish local variables in a member function from actuall class members and function arguments (which, btw, are denoted by the first letter capitalized, prefixed by a lower-case ''p'' if it is a pointer to something, or prefixed by a lower-case ''r'' if it is a reference to something).

Having an IDE which indicates type is great, but not all programmers use such IDE''s. And also, a 10 page print out of a member function would tell you if "foobar" belongs to the class, is an argument, or a local variable. (Oh, and dont get me started on global denotation

I guess, in conclusion, use what you think is best. IMHO, it never hurts to have you variable names be a bit more exacting; of course, where to draw that line will always be debated.

Regards,
Ro


Eagles may soar, but a ferret will never get sucked into a jet engine!

Share this post


Link to post
Share on other sites
A little doesn''t hurt - I agree with people here - pointers, sometimes arrays, member/static is sometimes useful.

I find myself often using ntimes and bfinished and similar just for simple integers and booleans used within my code, but that''s about it.

So simplified, its useful.

Share this post


Link to post
Share on other sites
If you avoid using pointers as much as possible (e.g. use references and containers such as vector) you can do away with the p too for most normal code.

Share this post


Link to post
Share on other sites
I use m_ and pp but nothing else. In particular I don''t use C in front of class names.

I think m_ is fine because it''s not tying to signify type but rather scope. Yes you could use this-> instead but that''s a bit to wordy for me. I don''t distinguish between ordinary members and static members.

I don''t think plain pointers need a p prefix. The fact that you''re using -> instead of . is plenty to tip the reader off that this is a pointer. I''m not sure why I continue to use pp. It just works for me.

I try real hard not to use globals. On those rare occasions I do use them I create a Global namespace, i.e. Global::some_var.

Share this post


Link to post
Share on other sites
I use a ''lite'' version of this. Scrap the C for classes, but the m_ for members, the sz for strings - etc.

I even use this in scripting, when things are typeless. Mainly because it helps me figure things out.

Share this post


Link to post
Share on other sites
quote:
Original post by Oxyd
Also - if you see
if (time >= 1.0) ...    
then it is clear, that ''time'' is a double.
It''s also clear that the programmer is a novice, given that floating-point values shouldn''t be compared for inequality in any fashion. Use an epsilon instead.

quote:
Original post by dmikesell
Was it ever necessary in the first place?
Yes. It''s roots lie in assembly programming, where type doesn''t exist. It was a mnemonic device, if you will, to indicate the usage of variables - not type. That''s where everybody got mixed up, and where it became useless. Type changes over time - see the various obsolete Win32 prefixes, for example - but usage is fairly consistent.

Today, without significant identifier length limitations (some old assembly source files allowed only 16 characters per line), usage can be indicated through intelligent variable naming. With our fancy IDEs today (and if you''re not using an IDE with IntelliSense-type features, you''re a masochistic moron), type information is available on hover. Throw in good comments and other code refactoring practices, such as reasonably-sized code blocks, and Hungarian notation is completely unnecessary.

I''ve been programming for eleven years. I''ve never found it necessary. Caveat emptor.

Share this post


Link to post
Share on other sites
I think some of the posters have been lone-wolves... perhaps never being thrown in to a situation where you take over another engineers code that didn''t bother to comment, document or perhaps have any standards at all. Then you do have the luxury of coding however you like, because you are likely to understand what you did...

Thing about alot of engineers is that they expect someone to know why i = j + k * cop; might be there with no explanation; Where i could be a local variable, j a class (or module) and cop an extern import.

This happens ALOT in real life - some one retires or leaves a company and someone has to keep maintaining the product.

So Hungarian Notation did have a place, and still does depending on language. It''s place in the likes of Java and C# seems very limited though.

I must say I am suprised about the anti-feeling that''s around to it right now, back in university a few years ago I''m sure it was encouraged by some tutors.

Share this post


Link to post
Share on other sites
No, I''ve worked in a large project. The fact was it was one that mostly used classes and STL templates. HN was woefully inadequate for describing their stuff, as you''d usually have the same damn prefixes everywhere, and they wouldn''t tell you much.

So, we did our own, simplified HN, and just said "give your variables friggin'' long informative names". The important ones were pointer, if a basic type then use the type names, if a class use class, and if an object then you''ve gotta be informative in the name. And we had to make new ones for all the STL containers (vector, hashmap, etc).

HN is a good idea, but using it "as is" is unfeasible.

Share this post


Link to post
Share on other sites
Well I will say that I was greatful for hungarian notation when I was tracing through a coworker''s inter-language glue layer written in C++ that had C, Fortran and C++ strings in one routine (example: szName, sfName, and sName). It made it easy to figure out that the problem was not at that layer.

Share this post


Link to post
Share on other sites
quote:
Original post by paulsdsrubbish
I think some of the posters have been lone-wolves... perhaps never being thrown in to a situation where you take over another engineers code that didn''t bother to comment, document or perhaps have any standards at all. Then you do have the luxury of coding however you like, because you are likely to understand what you did...
Completely orthogonal to the discussion. What is a good idea and what you are required to do at work are mutually exclusive, though occasionally coincident, concepts.

quote:
I must say I am suprised about the anti-feeling that''s around to it right now, back in university a few years ago I''m sure it was encouraged by some tutors.
It''s called the Tipping Point. Eventually an idea - good or bad (good: Hungarian Notation is now redundant; bad: "low-carb lifestyle") - gains enough steam that it begins to force the hands of others to some extent, even if they don''t necessarily agree (a morally ambiguous example: women''s low-rise jeans - some like it, some don''t, but it''s hard for women to find stylish jeans with comfortable waistlines).

I think that about covers it.

Share this post


Link to post
Share on other sites
It''s getting a lot of flack in this thread so I thought I''d offer it a little support. Brace yourselves...

I use Hungarian Notation.

if (time >= 1.0) does not necessarily imply that the variable "time" is a float. Sure, it had ought to be, but for what little trouble it is to type "f" or "d" before the variable name, I think it''s worth it. Though there is effectively no logical difference between

if (iTime >= 1.0)

and

if (fTime >= 1.0)

there are instances when it would be useful to know what each one is...if you''re working with the code and need to fix something. I think we can all imagine a situation in which we might need to know the particular type of "time" (or whatever) before we do something. Even if we can determine the type on the fly, it''s it irreverent?

But hey, with fancy IDEs, good comments, and good memories, maybe it''s not necessary at all. I seem to remember writing BASIC code (on an Apple IIe when I started programming, 13 years old?), I only used variables named with one or two characters, and always I created and used them in alphabetical order.

int A
string B
int C

And I didn''t use comments, subroutines, or really anything other than GOTO. I don''t think I even used "if". What''s the point of complex variable naming when you don''t use "if".

Peace, all.

Share this post


Link to post
Share on other sites
Hunagrian notation may be useful if you''re passing undocumented code back and forth between people, but I comment my code extensively anyways.

Also, for beginners, hungarian notation is a nightmare. I remember staring at lines of:

LPCSTR lpCmdLine;
int m_Integer;

And wondering what the heck everything was supposed to do. Typedefs and defines are fine, if they are very obvious:

GLbool Boolean;

Is fairly obvious, but beginners would seize when trying to decode ''LPCSTR'' and stuff. The ''LP'' for Long Pointer also got me when I was working with DirectX, because I couldn''t figure out why I had to use -> instead of . .


-- Fyhuang, president, Altitude Technologies

Altitude Technologies: http://www.hytetech.com/altitude
Altitude Forums: http://s8.invisionfree.com/Altitude_Forums/

Share this post


Link to post
Share on other sites

Personally, I have found that it's more valuable to use variable notation to express the scope of variables rather than their types.

For instance, it is pretty obvious that NumPlayers or PlayerCount is some type of integer, that PlayerName is some type of string, and that IsPlayer is some type of boolean, so hungarian notation IMO becomes redundant if you name your variables descriptively.

I do, however use the following notation:

m - for member variable
g - for global variable
x - for function parameter
- no prefix for local variables
p - for pointers
C - for classes


Take the simple example of an accessor function that sets the value of a class member:

void CSomeClass::SetSomeInt(int xSomeInt)
{
mSomeInt = xSomeInt;
}


I can immediately tell that I'm setting the object's copy of SomeInt to whatever value was passed in externally without referring to the definitions of mSomeInt and xSomeInt. Notating in this way gives me a hint as to how long those variables will be in memory, and what other code has access to them, without having to go back and look up how they were defined.


[edited by - EvilSteve on June 10, 2004 3:01:39 PM]

Share this post


Link to post
Share on other sites
Indeed, I agree some small ammount of notation is handy.

I use the prefix of "in" for all incomming function variables, "t" for temp variables within a code block, "m" for member variables and "g" for the exceedinly rare occasions I have globals.

I see no need for pointer identification.

Share this post


Link to post
Share on other sites
quote:
Original post by Pxtl
The important ones were pointer, if a basic type then use the type names, if a class use class, and if an object then you''ve gotta be informative in the name. And we had to make new ones for all the STL containers (vector, hashmap, etc).

This sounds like a very strange idea. One of the things I love about the STL is the possibility of seamlessly switching from one container class to another by simply using the iterator interface - by using and enforcing variable prefixes you completely lose that ability. (I have a tendency to use typedefs in all my classes, e.g. typedef std::vector<message> msg_list, simply in order that I can later switch to a linked list, dequeue, or whatnot if I discover that my original choice of data structure was unsound.)

Share this post


Link to post
Share on other sites
For every code sample I see on the board that prefixes classnames with C I kill one kitten.

Think of the kittens.

Share this post


Link to post
Share on other sites
I use m_ on class member variables to make it easier to remember which variables are part of the class and which are simply variables (local or parameters. Globals are evil).

I also use the data type prefixes more as a reminder to myself. Yes, the compiler will usually stop MOST (but not all...) data type mismatches, but it's just kind of a comfortable for "plain old data" data types. I don't bother for member classes, though, as I think "CGraphicsEngine m_GraphicsEngine" is descriptive enough.

Furthermore, an abbreviated prefix can make variable names a lot shorter, without losing any descriptive value, which is just easier to deal with. Example: iRows vs. NumberOfRows (or even NumRows). It gets a lot worse with complex variables.

I use p for pointer identification because, well, stuff like this can happen:


void DoSomething(int iBunchofStuff,int iNumIterations)
{
for(int i = 0; i < iNumIterations; i++)
{
DoThirdThing((DWORD)iBunchofStuff++);
}
}
void DoSomethingElse(int* iBunchofStuff,int iNumIterations)
{
for(int i = 0; i < iNumIterations; i++)
{
DoThirdThing((DWORD)iBunchofStuff++);
}
}


In the above, both of these functions are valid, and yet they do two COMPLETELY different things. ipBunchofStuff would make life much easier for someone who might have to go and change things later, and would, again, PREVENT BUGS.

Simply put, it's a simple notation and it reduces bugs.

I prefix all class names with "C" because, well, a class is not the same thing as a struct, nor is it even close to being the same as a primitive data type.

A struct CAN BE more or less the same thing as primitive data types (and, indeed, that's the only reason I use them -- for cases where an object has no member functions, nor does it need them), so I don't bother with the prefixing.

quote:

For instance, it is pretty obvious that NumPlayers or PlayerCount is some type of integer, that PlayerName is some type of string, and that IsPlayer is some type of boolean, so hungarian notation IMO becomes redundant if you name your variables descriptively.



I agree with this to some degree, but consider the following:

   
struct Vert
{
float x,y,z;
float nx,ny,nz;
float tu, tv;
};

struct Vec
{
float x,y,z;
};


With the above, it's EXTREMELY likely that you'll have functions that perform similiar operations on the two (and possibly between the two). It'd probably make your code less bug prone to affix a standard prefix to variables of either type (for example, v for vectors and vrt for vertices).

Not only that - it gets you into good habits. Not all programming languages are type safe (and, hell, not even C/C++ is 100% typesafe all the time). It can get ugly.

Having actually programmed professionally in an environment where a language that was NOT typesafe was used, I can speak volumes on the nightmare of working with code that doesn't use notation. No error was thrown when I assigned the value 27.48466 to the varialbe "CustomerName". That's right - no error.

You might be saying "well, that's just a stupid language", and I'd probably agree with you frequently - unfortunately, due to the functionality required for things like JIT to work 100% of the time, future languages will probably support more "features" like that (dynamic typing). It might be something as "minor" as not having unsigned values at first, but eventually the designers may very well say that the type of the data doesn't "really" matter, and that it would be "more efficient" for the compiler to treat all data as generic...and then things get ugly.

The reality is that MOST people don't understand how useful the notation is, even if it seems slightly redundant, until they've had to experience something like that.

Some other things

- I make extensive use of Singletons for application-wide objects, which I reference via macro:


template <typename T>
class CSingleton
{
// Stuff

};

#define EntityManager CEntityManager::Instance()
class CEntityManager : public CSingleton<CEntityManager>
{
// Stuff

};


That allows me to simply call EntityManager.DoStuff() in my programs. Since CEntityManager isn't a primitive data type, and nobody is going to try to assign values to it (if I was working with anyone THAT dumb, I'd kill them), it's not really necessary to prefix it.

quote:

It's also clear that the programmer is a novice, given that floating-point values shouldn't be compared for inequality in any fashion. Use an epsilon instead.



Hardly required for > / < comparisons, since floating point accuracy is very rarely off by more than a few thousandths of a point. Epsilon values are mainly needed for exact equality operations. You're wasting clock cycles if you use epsilon values for >, unless you actually need to be 100% exact. 9 times out of 10, though, you don't need exact figures anyway when dealing with floats.

quote:

Having an IDE which indicates type is great, but not all programmers use such IDE's. And also, a 10 page print out of a member function would tell you if "foobar" belongs to the class, is an argument, or a local variable.



Ok, seriously. It's 2004. Why on EARTH would you print out a 10 page code listing? Even the free IDE's out there provide better functionality than that antiquited methodology yields. You can't honestly think looking at reams of PAPER is better than typing an extra letter or two in front of variables, but anyway..

[edited by - Etnu on June 10, 2004 12:39:45 AM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
quote:
Original post by serratemplar
if (time >= 1.0) does not necessarily imply that the variable "time" is a float. Sure, it had ought to be, but for what little trouble it is to type "f" or "d" before the variable name, I think it''s worth it. Though there is effectively no logical difference between

if (iTime >= 1.0)

and

if (fTime >= 1.0)



it''s a float...

if (time >= 1.0) //time is a double
if (time >= 1.0f)//time is a float
if (time >= 1) //time is an int

Share this post


Link to post
Share on other sites
quote:
Original post by Etnu
...
...
...
[edited by - Etnu on June 10, 2004 12:39:45 AM]

The answer is:

Comment your code!

That way it is clear what you are doing, whether you are dealing with a vertex or a vector, etc. (plus, in that case, it should be clear which one you are dealing with, becuase both will probably only exist in containers).

To answer your "iPlayers is shorter than numPlayers": Yes. However, numPlayers is more descriptive, and it does not require a name change if the underlying type is changed. Anyways, your code will be a lot longer from the other prefixes.

Also, what do you do for functions? Do you prefix the function with a type? Or do you make overloads for everything?

Templates?

Why not just comment?

[edited by - thedevdan on June 11, 2004 3:12:54 AM]

[edited by - thedevdan on June 11, 2004 3:13:09 AM]

[edited by - thedevdan on June 11, 2004 3:13:37 AM]

Share this post


Link to post
Share on other sites

  • Advertisement