• Advertisement

Archived

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

Hungarian or, anyone, anyone??..

This topic is 5150 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 am pleased to say that my skills as a programmer have gone beyond those of the intermediate user and I am really excited to be moving onto the more advanced (for lack of a better word) stuff. I hope. I find my code however lacking a certain consistency and am seriously thinking of writing my code to conform to a certain standard. But the only one I have heard about is the hungarian notation. Do any of you guys recommend this, or are ya''ll aware of anything else? Thank you for your time.

Share this post


Link to post
Share on other sites
Advertisement
I personally dislike Hungarian notation, and strongly recommend against it''s use in new projects. Here''s one article by authors who aparantly agree with that sentiment.

Also there''s more to coding standards than how you write your variables. I generally give out this link in any thread mentioning coding standards. It''s a perl script to write your own coding standard. It has explanations for many of the sections, to explain why anyone would bother codifying certain sections.

Share this post


Link to post
Share on other sites
I personally dislike Hungarian notation really, really badly. There was a thread about coding style not too long ago on this board if my memory serves me well. You could search for it to see what the different members of this forum use.

SiCrane: I love the article you linked to. I read it a while back(who knows you might of been the one who posted it then) and I loved it.

Share this post


Link to post
Share on other sites
As for what to use? I''d say try to think about what you want to use. What feels right and looks clean to you and use it. Just try to be consistent in your style/notation.

Share this post


Link to post
Share on other sites
I prefer exdented style (not as cramped as K&R), with CappedVariableNames, CappedMethodNames, and UndecoratedClassNames (no ''C'' or ''I'', due to the nature of inheritance and polymorphism). g_ for globals, m_ for member data, and no spaces around punctuation, except math operators. e.g.:

for(int ind = 0; ind < Num; ++ind)

y = (16 + e) & (er << 2) * 32;

Later,
ZE.

//email me.//zealouselixir software.//msdn.//n00biez.//
miscellaneous links

Share this post


Link to post
Share on other sites
I''ve worked with Hungarian a bit, and I really haven''t been able to convince myself that it''s an actual advantage.

Personally... I like clear and descriptive names, and to me, Hungarian, by putting a bunch of encoded, acronymed bull**** up front, is an eyesore.

At work, we used a very lightweight convention for variable naming:

prefix a class data member with "f" (for data Field)
prefix a global with "g"
prefix a static variable with "s"
prefix a member function with "m"
prefix a typedef or class name with "t" (for Type)

so a simple class def would look like

class tStupidClass
{
protected:
int fWorthlessInt;

int mGetWorthlessInt( void ) { return fWorthlessInt; }
};

We also had conventions, and I think these were very important, for naming constants and enums, so

typedef enum eEnum {
kOne,
kTwo
} eEnum;

so an group of enums was always prefixed with "e", and any constant, not just enums but #defined constants and other constants, got the "k" prefix.

without the Hungarian prefixes I had a tendancy to use long, descriptive names for the variables that might tell me something about them. Like fSomethingList or fSomethingVector... But sometimes I wouldn''t bother, like if there was a general tendency to default to ints to like, count simple quantities, then the type of fNumKillerRobots wasn''t exactly a mystery that required a secret Hungarian code to decypher.

To me the most immediately useful piece of info about a variable was it''s scope (is it global, part of this class, is a function global or a member?), and whether or not it was a #defined or enumerated constasnt, and this naming convention encoded that.

The argument for hungarian is that, at a glance, you can tell the exact type of a variable... I guess that''s useful (I mean seriously, it is) but in practice I did not find myself handicapped by a naming convention that did not encode this... Mostly it just wasn''t a problem, but seriously, with the class browsers built into modern development environments and whatnot, it''s not THAT big of a deal to just look at the freakin'' header to find the type of a variable, and before long you get used to the codebase and the classes.

Having worked with both, I just feel like Hungarian just ads lots of obtuseness, supposedly for the sake of clarity, but it really doesn''t work for me. I like to go for longish, usefully descriptive variable names, and to me using Hungarian hurts clarity.

Share this post


Link to post
Share on other sites
Oh, I forgot to mention. If you feel you are at the point where you want to think about things like coding style, pick up a copy of Code Complete by Steve McConnell. This will tell you more about good coding practice than I or probably anyone else on this forum can.

This is like The One True Software Engineering Book that''s of actual value to people out there writing code, not teaching software engineering courses.

Here''s it''s page on Amazon
http://www.amazon.com/exec/obidos/tg/detail/-/1556154844/103-2101245-6527868?v=glance

[Edited by - The_Incubator on June 14, 2006 2:15:29 PM]

Share this post


Link to post
Share on other sites
quote:
Original post by The_Incubator
This will tell you more about good coding practice than I or probably anyone else on this forum can.

This is like The One True Software Engineering Book that's of actual value to people out there writing code, not teaching software engineering courses.



To be taken with a grain of salt though - C++ was not standardized in 1993 (and I don't think people here use much Ada or Pascal), and advice valid for C isn't necessarily valid for today's C++. "Industry best practices" have changed in 10 years. Still a good book though, so long as you remain critical.


“Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.”
— Brian W. Kernighan (C programming language co-inventor)


[edited by - Fruny on January 14, 2004 3:31:23 AM]

Share this post


Link to post
Share on other sites
Use the ALF coding standard. Mostly the prefixes and suffixes in the ALF coding standard let you know what the variable can do. Few reminders on what you have to do. Like some virtual functions that Must call their base class version will be prefixed with V, anyway, here. See for yourself...


Coding conventions used

- All class and struct names start with capital letters.

class Graphics;
struct Vertex;

- All variable names start with lower case (unlessed prefixed) and no spaces

int myVariable;
Graphics graphics;

- All member variables of classes start with m_

class Class { int m_privateVar; }

- All global variables start with g_

int g_globalVar;

- typedefs have a _t postfixed at the end of them

typedef float Time_t;

- Function pointer typedefs have a _pfn postfixed to the end of them

typedef void (*MessageHandler_pfn)(Message*);

- A class that starts with s_ means that it is a static class

class s_Math { public: static int Random() { } };

- A class that starts with the letter I means it is an iterface

class INode { virtual void F1() = 0; virtual void F2() = 0; };

- All enums start with ''e''

enum eObjectTypes { };

- All enum members are capital with underscores between words

class eObjectTypes { OT_EXPLODABLE, OT_BENDABLE };

- A solid base class (a class that should be derived from but has not vertual methods) starts with sb_

class sb_Movable { Vertex_t m_pos; void Method1() {} void Method2() {} };

- All static member vars start with ms_

template< typename T > class Singleton{ T* ms_pSingleton; };

- All static vars start with s_

static int s_dumbo;

- All pointers start with p

int* pInt;
Graphics* pGraphics;

- All smart pointer types have a <TypeName> with Ptr prefixed at the end. Example: Smart pointer
version of the Graphics class is called GraphicsPtr

typedef boost::shared_ptr<Graphics> GraphicsPtr;

- All macros are capital

#define NUM_OF_ENEMIES 30

- All global functions/macro functions start with some abbreviation specific to your project (This is preferable).

#define msAssert( p1 ) /* ms for Microsoft */

- Virtual functions have a V prefixed to the start ONLY if the abse virtual function has to be called

class Base{ VCallMe() { // do stuff } };

class Derived : Base { VCallMe() { // do stuff; Base::VCallMe(); } };


- Classes that should be derived from for a little extended functionalitybut are not interfaces start
with a V

class VTimer{ virtual GetTime() { return 0; } // Otehr functions };

class QueryTimer : VTimer { GetTime() { QueryPerformanceCounter(); } };
class MediaTimer : VTimer { GetTime() { timeGetTime(); } };

- Use consts instead of macros when possible so they maintain namespace qualification

namespace Name { const int NUM_OF_ENEMIES = 30; }

- Everything goes inside a custom namespace


| C++ Debug Kit :: GameDev Kit :: DirectX Tutorials :: 2D DX Engine | TripleBuffer Software |
| Plug-in Manager :: System Information Class :: D3D9 Hardware Enum | DevMaster :: FlipCode |

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Which of these ways do you guys use for member variables?:

A) int mMember;

B) int m_member;

C) int member;

D) Some other way, please show...

Share this post


Link to post
Share on other sites
quote:
Original post by Anonymous Poster
Which of these ways do you guys use for member variables?:

A) int mMember;

B) int m_member;

C) int member;

D) Some other way, please show...


int member_;



--
Dave Mikesell Software & Consulting

$ rm * .o
.o: No such file or directory
$ ls
$ ls
$ ls

Share this post


Link to post
Share on other sites
For member variables of a built in type i use m_ followed by the first letter of the type the variable is - for an example int m_iSomeInt, float m_fSomeFloat.

For pointer member variables i use m_p, or if the variable is of a user defined type i just use m_.

For globals I use the same style as above but use g_ instead of m_.

In naming classes I prefix them with C, structs are dont have any prefix but i put _s at the end of the struct name or _t if i declare a variable of the struct at the end of the declaration:

struct SomeStruct_s
{
//blah
} SomeStruct_t;

Share this post


Link to post
Share on other sites
What is Hungarian Notation? (as a Hungarian, ive never heard about it )

"Knowledge is no more expensive than ignorance, and at least as satisfying." -Barrin

Share this post


Link to post
Share on other sites
quote:
Original post by orbano
What is Hungarian Notation? (as a Hungarian, ive never heard about it )

"Knowledge is no more expensive than ignorance, and at least as satisfying." -Barrin


http://www.google.com/search?hl=en&ie=UTF-8&oe=UTF-8&q=hungarian+notation



--
Dave Mikesell Software & Consulting

$ rm * .o
.o: No such file or directory
$ ls
$ ls
$ ls

Share this post


Link to post
Share on other sites
quote:
Original post by orbano
What is Hungarian Notation?
Back when most code was written in a text editor in assembly language, there was no intuitive way to determine the "type" you were using a register to represent. Variable names were also constrained (some early assemblers allowed only 8 or 6 characters), so a Hungarian programmer working for Microsoft advocated a system for identifying variables within the company''s code. That system came to be known as Hungarian Notation, and is the reason for weird type and parameter names in the Win32 API (HWND? LPARAM?)

A Google search should bring up much more information.

Personally, I don''t use any notational system. I have an IDE, and it autocompletes as well as displays type and access information when I hover the mouse over a variable. I use consistent conventions - camelCase for methods, CapitalizedNames for classes and interfaces and set indentation (2 spaces per scope).

Share this post


Link to post
Share on other sites
quote:
Original post by Anonymous Poster
Which of these ways do you guys use for member variables?:

A) int mMember;

B) int m_member;

C) int member;

D) Some other way, please show...


int member
this->member
Conveys scope and brings up the intellisense window.

Share this post


Link to post
Share on other sites
The arguments against hungarian and related notations are spurious at best.

If you make a change from this:

int iVariableName;

to this:

float iVariableName;

you ought to be reprimanded! The correct change is to this (or something similar):

float fVariableName;

After you hit compile, the compiler will kindly point out all the places the change has impacted and you can make a cursory check to see if you inadvertantly changed anything else as you make the name change (like with printf or an equality check).

Another reason this sort of notation is great is for converting types. For example, there are lots of useful and/or necessary functions that you can''t change that require a variable conversion to a type you don''t have. Here is a little Win32 convenience function I wrote a long time ago:


std::string GetBoxText(HWND hdlg, int iDlgItem, bool bCombo)
{
UINT uMsgSelection = 0;
UINT uMsgText = 0;
UINT uMsgLength = 0;

if(bCombo == true)
{
uMsgSelection = CB_GETCURSEL;
uMsgText = CB_GETLBTEXT;
uMsgLength = CB_GETLBTEXTLEN;
}
else
{
uMsgSelection = LB_GETCURSEL;
uMsgText = LB_GETTEXT;
uMsgLength = LB_GETTEXTLEN;
}

int iSelection = (int) SendDlgItemMessage(hdlg,iDlgItem,uMsgSelection,0,0);

if(iSelection == LB_ERR) // -1 == CB_ERR == LB_ERR

return "";

UINT uNbrCharacters = (UINT)SendDlgItemMessage(hdlg, iDlgItem, uMsgLength, iSelection, 0);

char* szText = new char[uNbrCharacters + 1];
SendDlgItemMessage(hdlg, iDlgItem, uMsgText, iSelection, (LPARAM)szText);
std::string sText = szText;
delete [] szText;
return sText;
}


Notice the szText and sText both contain the text of the selected item in the list box. They have the exact same function and contents and differ only by type. Anytime you need to convert one variable into an identical one that varies only by type, hungarian notation is great!

Share this post


Link to post
Share on other sites
I stronly agree with The_Incubator, that the most important information about an identifier is its scope (if it''s a variable). I might go farther than some people would prefer, by also indicating an identifier''s category (class type, simpe type, var...), but I am not inclined to label what type every variable is.

All types are represented by a character and an underscore, so:

c_ClassName
i_InterfaceName
t_BasicTypeName
s_StructName

All variables are represented by just a character:

mMemberVariable
sStaticVariable
gGlobalVariable

I''ve considered using ''l'' for local variables, but I just leave local variables alone and put no prefix on them. (The same goes for functions of all types). I''ve also considered using ''c'' for constants, but I''ll probably just stick with all caps, since ''c'' might get confused with ''c_'' too easily, and no one would quickly recognize ''c'' to mean constant.

I do make a special case for pointers, and add an extra character ''p'', since it is a bit more important to be clear that a pointer is a pointer, since so many bugs are related to them, so for pointers:

pLocalPointer
mpMemberPointer
...

And one last thing, function pointers, since they are even odder than simple pointers, I certainly want to make it clear what they are:

fpLocalFunctionPointer
mfpMemberFunctionPointer
...

My methods may be a tad overboard, but I''d rather go overboard than underboard.

Share this post


Link to post
Share on other sites
quote:
Original post by Rick Scott
The arguments against hungarian and related notations are spurious at best.
No, they aren''t. It''s easy to say that you should change iVariableName to fVariableName with a type change and then let the compiler point out all the affected lines; the question is, what''s the upper bound to the possible number of affected lines? What if the variable name is actually a function or type name in a library that has already been released, meaning you can''t change it without breaking all code that depends on your library? There''s a reason why many of the Win32 types don''t match the indication their Hungarian Notation names provide: WPARAM and LPARAM are just two trivial examples.

Hungarian Notation is bad because it exposes implementation details rather than hiding them.

quote:
Another reason this sort of notation is great is for converting types. ...Anytime you need to convert one variable into an identical one that varies only by type, hungarian notation is great!
Uh, no. Any time you need to convert one variable into an identical one that varies only by type, you have too many times. A char * is not the same as a std::string; the difference is more than just "type", it''s functionality. Furthermore, to convert between the two, std::string takes a null-terminated (C) string as the argument to a constructor or an assignment, and provides the c_str() method. A more intelligent thing to do would have been for you to simply get the raw control text and assign it to a std::string - no need for notation of any sort.

Rather than refuting a widely-accepted option or practice because you don''t share/do it, try taking a good look at its merits and demerits.

Share this post


Link to post
Share on other sites
I coded without Hungarian notation for about 7 years. I''ve been using it reliably for about 5 years now. Here''s my run down: It''s generally positive, but has been over-used and abused.

Warts - readability vs writeability
The primary gain of the "warts" is readability - not writeablity. Simply put, it is harder to write hungarian code. It takes more thought and more keystrokes, and there is the infamous argument about changing the wart when the type changes. Yes. It''s harder to write. Get over it. It makes up for it in readability. When you are knee deep in someone else''s code, it''s nice to know at a glance what all the data types are. What''s integer, what''s float, what''s an object.

Warts - Overcomplicated
Many people have overdecorated their variables, created and combined too many warts. Some people even try to create a new wart for every class. They have a list of 100''s of warts that you must know in order to decipher their meanings. This is where Hungarian notation really takes it in the nads. In order to effectivly use warts, your list of warts must, MUST, be small. I use only the following warts, (i, f, c, obj, ctrl, e, t, x, p, a). The emphesis here is on usage - not definition. For example, both an array and a std::vector both get an ''a'' wart. They''re both USED as arrays. If you try to precisely define a variable with warts, you''re just creating confusion. Lable it simple. It''s just a hint to the future reader - not a definition.


Getting started
For 6 months to a year, you''ll hate it. Most people arguing against Hungarian notation are in this category. In order to give it an honest evaluation, you have to use it for a while. If you really want to prove that Hungarian notation is bad, try to find someone who used it (40 hrs a week) for over 4 years who really doensn''t like it. Most expreienced hungarian programmers acknowledge it''s weaknesses, but still agree it has more advantage than not.



-----------
VenDrake

"My stupid jar is full. I can''t talk to you anymore."

Share this post


Link to post
Share on other sites
quote:
Original post by Oluseyi
No, they aren''t. It''s easy to say that you should change iVariableName to fVariableName with a type change and then let the compiler point out all the affected lines; the question is, what''s the upper bound to the possible number of affected lines? What if the variable name is actually a function or type name in a library that has already been released, meaning you can''t change it without breaking all code that depends on your library? There''s a reason why many of the Win32 types don''t match the indication their Hungarian Notation names provide: WPARAM and LPARAM are just two trivial examples.



I would never advocate using hungarian notation on functions (except pointers to functions), or on types. And if you have 1000''s of lines of code using a single variable, and you change it''s type, you better damn well go through each line because odds are you affected something somewhere. With hungarian, you have the compiler to police you in this regard (to a certain extent).

Even if I didn''t use hungarian, I would still go through all the uses of the variable. A type change is usually a big deal, not something you can change and hope (or change and forget about).

quote:
Hungarian Notation is bad because it exposes implementation details rather than hiding them.


Not for variable names. Hiding implementation details is the job of a good OO design. If you are accessing variables directly in a class or struct, you better believe the class-implementer should be made VERY aware of type changes as soon as possible.

quote:
Uh, no. Any time you need to convert one variable into an identical one that varies only by type, you have too many times. A char * is not the same as a std::string; the difference is more than just "type", it''s functionality. Furthermore, to convert between the two, std::string takes a null-terminated (C) string as the argument to a constructor or an assignment, and provides the c_str() method. A more intelligent thing to do would have been for you to simply get the raw control text and assign it to a std::string - no need for notation of any sort.



Did you see my example? How do you propose to get a std::string from a text box in the Win32 API? And you are being pedantic when you say they aren''t the same. If you re-read my post, you will see that I obviously meant they contain the same letters. They might do it differently, but if szText contains "Hello World" then sText will contain "Hello World".

quote:

Rather than refuting a widely-accepted option or practice because you don''t share/do it, try taking a good look at its merits and demerits.


I have looked at it, and found all the arguments agains to be frequent spurious, and sometimes downright misleading.

Share this post


Link to post
Share on other sites
quote:
Original post by Rick Scott
I would never advocate using hungarian notation on functions (except pointers to functions), or on types.
Good. Unfortunately, the company that made it famous - and exposed most programmers to it - did. Notice the lack of naming warts in their new APIs?

quote:
quote:
Hungarian Notation is bad because it exposes implementation details rather than hiding them.
Not for variable names. Hiding implementation details is the job of a good OO design.
Moot, given that many use it for more than variables. I''ve seen it advocated that accessor methods have warts to indicate the nature of their returns (beyond language type - orthogonal concepts like real-world units). In some cases this is debatable, however I would think that such accessors need to be renamed in the first place - getDistanceMeters() instead of getDistance_m.

quote:
Did you see my example? How do you propose to get a std::string from a text box in the Win32 API?
I didn''t. I proposed to get the C-string and assign it to a std::string. If the value extracted from the text box is handed off to a function expecting a std::string, the conversion will be implicit. If you wish to modify the std::string several times - pass it to a few functions by reference, for example - then it can be created within scope and modified appropriately:
std::string s = GetTextBoxText(...);
ModifyStdString( s );
ModifyStdStringAgain( s );
Your example solves a minor problem and has cohesion that''s too high.

quote:
And you are being pedantic when you say they aren''t the same.
No, I''m specific. Is an array the "same" as a std::vector containing the same elements? There''s a reason the Standard C++ Library constructs are called containers and the native C types are not. There''s a reason fairly automatic conversions exist in one direction, but not in the other.

quote:
quote:
Rather than refuting a widely-accepted option or practice because you don''t share/do it, try taking a good look at its merits and demerits.
I have looked at it, and found all the arguments agains to be frequent spurious, and sometimes downright misleading.
This I suppose I can''t argue with - and I really have no problem with it. It''s a matter of preference, until collaboration becomes a factor, so I apologize for the tone of my original statement.

Share this post


Link to post
Share on other sites
quote:

int member_;



Curious, this is the convention for the place I currently work at, as well. I''d never seen it before I started here, three years ago. (m_, f, and nothing were the three obvious candidates before that).

Share this post


Link to post
Share on other sites

  • Advertisement