How should a variable name indicate it's scope (member versus local versus static versus parameter names)?

This is one of the toughest and most hotly contested stylistic topics in C# code design.  Styles range from the use of pure Hungarian notation to the lack of any notation of scope at all.  It's not an easy problem because the design of the Managed languages leaves us with no obvious solutions.  Prefixing variable names clutters the workspace and adds information that may not be particularly useful.  Giving no indication of scope may lead to code ambiguity and in the worst case, actual code defects.  It's hard to generate a set of categorical rules for naming members -- following one convention may lock you in to a complimentary rule.  For example, if I prefix all member variables with 'm', I may feel that to be consistent, I should prefix local variables with an 'l'

I'll present some common conventions, and my thoughts on them.  Hopefully I'll get some good feedback on this from other managed developers.  (As an aside, I've been asked if these rules are applicable to C# only, or whether they should be applied to all managed languages.  I would answer that these are very C#-centric, but may have application in similar Managed OOPLs.  Rigid application of any of these rules may not make sense in something like VB.Net, and certainly won't make sense in Managed C++.)

  • Use full Hungarian notation
    • Pros
      • No ambiguity in variable scope
      • Immediately familiar to C++ developers who are migrating to C#
    • Cons
      • Vast amount of unnecessary clutter.  Types and scope are of less referential importance in Managed code which strictly enforces types and manages memory.
      • Uses underscores which will usually be an eyesore in well-formed managed code.
      • More typing and slower development.  Rigid conformity to an “unnatural“ system like Hungarian results in a lot of effort expended on maintaining proper names.
      • Harder to discern functionality when reading code.  The actual variable usage will be hidden under a stream of prefixes, which reduces its at-a-glance value.
      • Designed for C/C++, NOT for C#.
    • My opinion
      • Avoid this like the plague
      • There are a number of reasons to not use this style, and a pretty weak excuse to use it -- it's a standard.  It was not designed for C# and does not integrate itself well into the language.
  • Use underscore notation
    • Description
      • Prefix member fields with “_“ or “m_“
      • Optionally prefix parameter names with “_“, “i_“, or “o_“
    • Pros
      • Very strong visual cue about the scope of the parameter
      • Very simple system to implement and standardize on
      • Improves Visual Studio Intellisense lookups
    • Cons
      • Underscores are visible to the point of distraction
      • Using an internal field outside of the class leads to the “._“ situation (hard to read)
      • Particularly distracting when visually comparing external members (PascalCased)
    • My thoughts
      • I've seen many teams/individuals implement this system successfully.  It has, in the long run, made their code more maintainable.   However, I personally have trouble reading underscore notated code.  For me the underscores are too pervasive and have more “weight“ than the public members.  Again, I feel if I need the hint in the first place, then perhaps there should be more encapsulation or fewer locals occurring in the code.
  • Use semi-Hungarian notation
    • Description
      • Prefix member fields with 'm'
      • Alternatively, prefix local variables with 'l'
      • Optionally prefix parameter names with 'p', 'i', or 'o'
    • Pros
      • Can solve some of the ambiguity associated with locally scoped variables and uninitialized member variables
      • Very small amount of typing overhead
      • Organizes intelligence data by separating locals, members, and parameters into their own sections (alphabetical)
        • Potential Con Example:  You might have a case where you have a local variable 'msg' is grouped with member variables prefixed with 'm'
    • Cons
      • Often difficult to get multiple programmers to adopt such a “loose“ style
      • Camel casing can confuse the issue slightly.  If you have a private variable mMyString and a public property called MyString, those two names look similar enough at-a-glance to potentially introduce code defects.
      • If your classes have so many member / local interactions that you absolutely need a system for separation to keep things straight, it may be an indication of design issues.  Often, re-evaluating encapsulation, class hierarchy, and interface will give you more manageable code than simply using prefixed names as a band-aid.
      • Using 'i' and 'o' for parameter names is really only useful to the interface developer, not the end-user.  The end user's hint should be the out or ref keywords.  I rarely see public functions in which it would be easy to lose track of an output or an input.  There may still be some value in internal functions (particularly recursive functions).
    • My thoughts
      • I'm still undecided on this.  For readability, this style doesn't seem to help or hurt my ability to understand code.  If the objects are well formed, the prefixes usually aren't necessary in my class space.
      • I have used them myself, and I've found the biggest challenge is sticking with the scheme once I've started using it.  If I have a few member variables that I'm using one time each in two member functions, it's exceedingly easy to get lazy and not follow my own naming convention.  Suddenly my code is that much less readable for having used the convention in the first place.
  • No prefixes
    • Description
      • Perhaps the most “pure“ naming style is to stick to camel-cased variable names with no prefixes of any kind.  This gives the user no indication of scope at-a-glance and relies on the design and descriptiveness of the code to indicate object scope
    • Pros
      • Easy to write, and can be the easiest style to read.  If the developer has put effort into the class design, there should be no question of object locality purely on the basis of it's usage.
      • A very neutral style for team projects
      • Any ambiguities found may indicate problems with object design
      • Some dev tools will differentiate locals and fields by color anyways.  This style takes fullest advantage of those tools.
    • Cons
      • Large classes can become painfully unreadable if local variables are used liberally to interact with private data
      • Potential variable name overwriting can cause code defects
    • My Thoughts
      • This is my preferred modus operandi.  I am comfortable with this style because it helps me to think critically about my own data localization.  Used correctly, this is the most elegant solution, but can also lead to the most problems when dealing with many developers with a range of development experience.
  • Lowercase locals
    • Description
      • Drop camel casing for local variables.  Member variables will always be camel cased.
    • Pros
      • Locals (which aren't around very long) are easily identifiable
    • Cons
      • Still a level of confusion with single-word variable names (i.e. is index a local or a member?)
    • My thoughts
      • This system is essentially trumped by it's major Con -- you're using a system that itself cannot be relied on.
  • Abbreviated (short) locals
    • Description
      • Abbreviate all locals so that index becomes i and currentClient becomes cc.
    • Pros
      • Very immediate visual cue that you are dealing with a short-lived local instead of a member or parameter
    • Cons
      • Ambiguous, potentially hard to read, and possibly too much overlap
    • My Thoughts
      • I don't recommend this as a strict style of differentiating locals from members and parameters.  There are reasons to abbreviate and shorten variable names, but scope is not necessarily the only reason.  I'll describe this in more detail in part 3, where I'll talk about name descriptiveness with relation to usage and lifetime.
  • Using the this keyword
    • Description
      • Any time you reference a member variable, use this.varaibleName
    • Pros
      • You can use locals, parameters, and members with the same name
      • Very quick lookup of fields and methods available to the class.
    • Cons
      • Encourages use of locals, parameters, and members with the same name
    • My Thoughts
      • This annoys me more than just about anything I see in Managed code.  It's like a license to write sloppy code.  The this keyword has its place, but it shouldn't be abused to allow name reuse.
      • I do see an argument for this when using it for Visual Studio Intellisense lookups, but I would still remove the keyword after it has been used to do a quick search.  A good alternative to this is using a common naming convention (say, prefixing with “_“) and typing  “_“ and using the CTRL-SPACE to bring up a quickly formated list of members.  I'll be looking for a better alternative (a dedicated keyboard command?) and post here if I find it.

That's all for now.  I'll be posting part's 3 and 4 soon.  Part 3 will cover how to stylistically indicate object behavior using varyingly descriptive names.  Part 4 will cover grouping by name and styles I've encountered.  If you see anything I've missed, send me feedback, and I'll add a section here!