Saturday 5 December 2009

Apps Hungarian vs Systems Hungarian

Hungarian Notation is a convention where a prefix is given to a name to indicate its type. There are two flavours of Hungarian, and most of the criticisms are directed at Systems Hungarian, while people don't realise that Apps Hungarian even exists.

Systems Hungarian prefixes variable names with their type. One big argument against doing this is that if the type changes, then you have to change every occurence of that name to match the new type.

Apps Hungarian prefixes variable names with semantic information about the variable.

Without the prefix, "Filename" might be a string, a text box, or something else. "Car" could be an instance of the car class, or a pointer to a car, or an index into a list of cars. "First" and "Second" could be almost meaningless, but in a spreadsheet application (for example) they could refer to rows, columns, cells, or something else.

With a semantic prefix, things become clearer. In a forms application txtFilename is now likely to be the name of a textbox which contains a file name, while strFilename is more likely to be the string itself. Note that strFilename doesn't constrain me to any particular type of string - just that it is a string of some description.

"iCar" is a sensible index into an array of cars, "pCar" is a pointer to a car, and "car" is most likely to be a concrete instance of the car class.

My favourite example comparing Apps Hungarian to Systems Hungarian is based on spreadsheet software.

Using Systems Hungarian (prefixing the type to the name), if "first" and "second" are integer indices, the assignment "iFirst = iSecond" looks alright at first glance. However, if the two variables were refering to rows and columns respectively, then the assignment was used to assign incompatible values.

If we'd used Apps Hungarian instead, the assignment now becomes "rowFirst = colSecond" and without knowing anything about the type of the data, if we saw that assignment, alarm bells would be ringing.

A colleague told me that a 'p' prefix before a pointer name was unneccessary - His arguments were:
  1. we have strongly typed compilers which can tell us when we've tried using the variable incorrectly
  2. intellisense can tell us a type just by hovering the mouse
  3. if a name was followed by a dot '.' then it was a concrete instance
  4. if it was followed by an arrow '->' then it was a pointer.
My counter-arguments are:
  1. Wherever possible, I want to type code correctly in the first place - not have to wait for the compiler to tell me it's incorrect.
  2. Intellisense requires me to shift control-context to the mouse - which can be very disruptive during an intense coding-at-the-keyboard session
  3. Intellisense doesn't always get it right
  4. The code that has already been written isn't guaranteed to have used dots and arrows yet - explained below:
If you had a variable m_CurrentVehicle - and a member function, EnoughFuel(); which is correct? m_CurrentVehicle.EnoughFuel() or m_CurrentVehicle->EnoughFuel() ?
If the variable was named m_pCurrentVehicle, then you would be able to see the answer instantly.

I used to hate seeing things in Systems Hungarian like lpszMessage (long pointer to a string which is zero terminated), but I like Apps Hungarian.