NDepend Blog

Improve your .NET code quality with NDepend

Hungarian Notation for Fields in C#

April 21, 2021 6 minutes read

Hungarian Notation for Fields in CSharp

If there is one topic that divides the C# developers community, it is the Hungarian notation for fields. In our team we rely on Hungarian notation for fields, not just by habits but because we consider that it makes our C# code clearer. On the other hand the Microsoft Framework Guidelines advises: DO NOT use a prefix for field names and DO use PascalCasing in field names. However this guideline doesn’t apply to internal and private fields, only public and protected fields. If these guidelines were applied to internal and private fields, code would look like this.

Code-with-no-hungarian-notation

There are several motivations for not using fields Hungarian notation:

  • We can end up with a multitude of prefixes, different for every teams and projects, difficult to learn and maintain. Such potential anarchy is indeed easily solved by not abbreviating at all.
  • This clutters a bit the code and obfuscates a bit the purpose of the field.
  • It makes possible having m_Val and s_Val used in the same scope.

But should we be satisfied by the code above? Val1, Val2, Val13 and Val4 are fields with very different lifetimes and without prefixes we are forced to jump to their declarations to demystify.

Interestingly enough, the thousands of non-public static and instance fields in the .NET BCL (Base Class Library) implementation are prefixed with an underscore. Indeed, the BCL was written by C++ developers before there was a usable .NET. C# and the Framework Design Guidelines came after that. And in C++ such underscore prefix is more popular.

Fields-in-Base-Class-Library-Prefixed-With-Underscore

Advantages of code elements name prefix

Clearly there are advantages with prefixing. Why are we all starting our interface names with I? Since the .NET inception this guideline is popular. It became widely applied because prefixing interfaces with I makes the code clearer: interfaces are the roots of good OOP design and being able to identify if a type is an interface or not at a glance makes the code more readable and more maintainable.

I remember that, when developing the NDepend Visual Studio extension, most of the EnvDTE types were interfaces whose names are not prefixed with an I. It was odd consuming these interfaces that don’t look like interfaces. But it turned to be annoying to mock them in tests.

EnvDTE-Interfaces-Name-Not-Prefixed-With-An-I

Being an instance or a static field matters

I noticed that often developers are not rigorous about the class and object terminology: many uses the term object to designate a class. Thus one might not consider that being a class field (static) or an object field (instance) is an important fact. But those fields lifetime details are essential to understand from the source code what happens at runtime. I recently wrote about the proper usages of the keyword ‘static’ in C# that explains that the keyword static should be reserved only for immutable state.

We use Hungarian notation for fields for the same reason why everyone is prefixing interfaces with I: to get clearer code. Certainly habits play a role in this choice, but objectively this version of the code below contain more information than the version in introduction.

Code-with-hungarian-notation-3

Taking account that in the real-world the field declaration remain invisible when reviewing the field usages, this extra-information avoids to jump to the field declaration in case of doubt. And when one reviews code, one has plenty of doubt: anything that can relieve some doubt is welcome.

Other benefits

Another benefit of field Hungarian notation is that it makes such wrong call obj.m_State=3 obvious. A class should be responsible for its instances states and thus should encapsulate its fields by making them private. Note that this rule might not hold in high-performance environment like C# Unity because a property accessor represents necessarily a small performance hit. However most of the time it is worth encapsulating fields that are not suitable to be backed with the C# auto-implemented-property syntax int AutoProp { get; }.

Also prefixing fields leads to clear segregation between fields and methods when members of a class are listed alphabetically, both in the intellisense box…

Alphabetical-sorting-of-fields-in-intellisense-box

…and in the wizard bar:

Alphabetical-sorting-of-fields

Text editor could easily use a color scheme or some icons to differentiate the usages of static and instance fields. The Visual Studio standard code element icons actually makes a difference with a small circle between instance and static fields:

Standard-Visual-Studio-Field-Icon

But code is often read and edited within a raw text editor that don’t have support for icons. Moreover, unlike the small circle, the m_ and s_ prefixes intuitively convey the my/member vs. static point. Also those two prefixes are well-known enough: only complete beginners could thing that s_ would mean something like string or signed.

And this raise another debate: why Hungarian notation would be ok to precise the instance/static fields nature and not the field type? I’d say that – unlike the lifetime of a field – the name of a field should offer some hints about its type: m_FirstName is certainly not an int, m_IsDisposed is certainly not a string, m_Employee is certainly not a string either…

m_ prefix vs. a single underscore prefix

Many prefers to prefix fields names with an underscore. As we saw in the introduction most of the .NET Base Class Library private fields are prefixed with _.

But this underscore notation acknowledges the need to segregate properties, fields and parameters, but not the need to segregate static and instance fields. On the other hand a single underscore is more abbreviated than two characters and yet, solves many ambiguities As a result there is a trade-off here.

m_ prefix vs. this.

Some suggests to prefix instance fields usages with this.. The benefit of m_ over this. is that it’s 60% shorter but more importantly, there is no way to accidentally forget about the prefix. Indeed when the this. prefix is used inconsistently it becomes worse than not using it at all since this creates confusion.

Enforcing Consistency

Despite all the benefits listed I’d say that your field naming conventions doesn’t matters so much as long as you’re consistent. Those are details that can make the code a bit more clearer. But these same details can also frustrate a bit some members in the team that look at Hungarian notation as something of the past.

To prevent inconsistency you can use a code validation tool: all such tools have some rule to enforce identifiers naming. Moreover a rule to enforce field prefixes is much easier to write and customize than a rule that would check that this. is used everywhere it should. With NDepend writing such rule with a C# LINQ query is as easy as:

Btw the default rule Instance fields naming convention takes account of a bit more stuff like serialization, C# Unity conventions or delegate objects.

Conclusion

Most of us are working on large legacies with hopefully existing guidelines that are hopefully enforced somehow. These guidelines are applied for a long time and it would be counter-productive to change them. But the next time you start a new project with the opportunity for new guidelines, maybe the Hungarian notation will help writing code that is a bit clearer!

Comments:

  1. GreatAndPowerfulOz says:

    What you speak of is not Hungarian notation, but rather scope notation: local, member, static (aka global).

    Hungarian notation, as practiced, prefixes the type of the field to the name, as in ListOfCustBase or strName. This is bad.

    Hungarian notation, as originally intended, names the field for what it is or contains, as in Customers or Name. This is good.

  2. Hi,

    though I’m certainly in favor of prefixes for clarity, since it really improves reading, I would like to add two remarks.
    First of all, “real” hungarian notation is more than just m_ an s_. When we talk about hungarian notation in languages such as C++, the prefix also consist of a type identifier. For example, m_nAmount or m_fAmount, which not only told you it was a member, but also told you the type of that member. And if you have only notepad as an editor (which sometimes happens), then you would know that if you see something like if (m_bABC == m_nDEF) you are probably comparing apples and oranges.
    Second, I think in current .NET code, it is common to use the single _ for private members of a class, which I also apply and which is what I think you see in those MS libraries. The _ prefix avoids the this., which, as you rightfully point out, is a complete disaster an ugly habit of some people. the m_ or s_ adds very little value imho, because if you have a variable with the same name in your class, one begin a member and the other static, that can only be confusig for everybody

  3. Hi Patrick,

    The “DO use PascalCasing in field names.” guidelnine is preceded by this comment:

    “The field-naming guidelines apply to static public and protected fields. Internal and private fields are not covered by guidelines, and public or protected instance fields are not allowed by the member design guidelines.”

    The rule doesn’t apply to the examples.

  4. The BCL was written by C++ developers before there was a usable .NET and C#.

    The Framework Design Guidelines came after that and because of that.

    this. is a language construct. Any other name mangling isn’t.

  5. Patrick Smacchia says:

    Thanks Paulo! I updated the intro based on your comments

  6. A bigger problem is the use of the var keyword. In the Method examples I had to scan multiple lines to determine the correct data type. In the “private” examples reading just the one line told me exactly the data types.

  7. Darryl Wagoner says:

    What you have described isn’t true Hungarian notation(HN). True would be iFoo for int value and sFoo for string value etc. What you are talking about is mapping (per Clean Code by Uncle Bob). His claim that mapping should be avoided because it requires a mental effort to translate in a person’s mind. When HN came out I thought it was a bang-up ideal until I started using it. I quickly learned it was more trouble than it was worth, then Uncle Bob explained why it was a bad idea.

    We live in a world of great IDEs that will tell you all about a variable. Why do we need to clutter up the domain meaning of a variable with mapping.

    If one feels they need to convey some non-domain information, then it should be suffixed not prefixed. In the example of avoiding “this” which normally happens in the constructer then have the parameter name suffixed with an underscore.

    In the case of a backing field for a property, then make it camel case and the property the normal Pascal case.

    Object names should with a few exceptions convey domain information, not programming constructs.

  8. This is bullshit. Do not use Hungarian. None of the touted benefits are actually benefits. You use one of the best IDEs on the market, it’ll tell you what type it is.

    Why would you neet to remember the type before you can use intellisense? Why add to cognitive load when reading code, which you do more than actually writing code.

    In short: if a company wants you to use this tripe: find another job.

  9. Felicity Pilchard says:

    Absolutely agree with what Wim VH said above about type, and it’s a very important point, BUT please note that “type” here does NOT mean [simply] the underlying hardware type of the variable! Simonyi’s original paper made that very clear. So an integer variable for apples and an integer variable for oranges should have different prefixes, which Wim VH’s “m_bABC == m_nDEF” example emphasises. The fact that this was not understood, and “type” misread as the hardware type, resulted in the silly “Systems Hungarian”, which led to Hungarian Notation getting a bad reputation.

  10. Microsoft isn’t consistent with their linked guidelines, either. For example, the .NET 5 runtime repo prefers using a prefix.

  11. Where .NET is using prefixes is in private members which is explicitly not covered by the Framework Design Guidelines.

    And when questioned, no sane reason was given by the team for that. It was carried on from the existing code and just written down for collaboration.

  12. To extend on Felicity Pilchards comment: A better example would be the use of prefixes (or suffixes) to differentiate between variables storing the same entity with a different representation or unit, e. g. floating point variables storing an angle value either in degrees or in radians could greatly benefit from a suffix “_deg” and “_rad” respectively. Or use different suffixes for string variables storing either encoded or decoded text.

    Also, the compiler will catch most data type inconsistencies anyway, so why bother with data type prefixes?

    Besides, if you are still using an editor that does not trivially provides you with type information, you have a more pressing matters to attend to than naming guidelines!

    That said, whether or how to indicate that a variable is a class member is a different question, but not entirely: IMHO the same reasoning behind _not_ using a type indicator in a name would lead to _not_ using a membership indicator. Therefore I’m leaning towards not using any prefix for member variables at all. In my IDE that’s not a problem at all, because I use a plugin that indicates membership by using a different text style and color, and more, using another text style and color for inherited member variables – something that couldn’t be achieved with a prefix alone!

    Tl; dr.:
    use prefixes or suffixes only if there is no other way to catch an inappropriate use: check the capabilities of the compiler and your editor/IDE before resorting to naming conventions. Naming conventions are prone to human errors, and it doesn’t help if they conflict with whatever your compiler and IDE indicate.

Comments are closed.