Поделиться через


Variable names in C# Part 2

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!

Comments

  • Anonymous
    July 09, 2004
    The comment has been removed
  • Anonymous
    July 09, 2004
    The comment has been removed
  • Anonymous
    July 09, 2004
    I like your reasoning, you left out the role of intellisense in this'ing class members. For what it's worth, I've found myself increasingly this'ing class members simply because it provides convenient access to the intellisense list. There's probably a hotkey to get the same list to appear, but my brain is already too full of application-specific hotkey memories.

    -Don
  • Anonymous
    July 10, 2004
    My only comment is that typing overhead is not a reason for turning a certain style down. I hear this too often in other contexts, where people want to abbrevate function names and variable names, just because its "faster" to write, like i instead of index etc. Most of the time spent developing is not spent typing, so the extra split second you have to spend typing it all out will gain you seconds a few weeks later when you come back to the code. I believe the reason most people don't want longer names is because they have a hard time coming up with the name for some odd reason.

    Personally I find it several times harder to read code that doesn't have scoping built into the names. I prefer a loose hungarian notation with underscores still in there for the scopes. With nice and readable variable and function names(that make sense). currentClient makes alot more sense than cc any day..

  • Anonymous
    July 10, 2004
    Don: Alt+RightArrow pops up the IntelliSense window. It's easy enough to remember for the visual of (fill in a name to the right of what I just typed).

    Largely I find in my code that local variables seem to most often fall into two categories:

    1) Indexes. Usually i, j, and k and "item" (foreach (Item item in List)) are all I need.

    2) Temporary Objects. One of the things that I find somewhat irksome, but happens all the time, is I need a brief object as a variable simply to set a few properties before passing the object to some method, usually where there isn't a constructor to do it. These end up often as "t" + Upper-Cased letters in classname. Example:

    MyClass tmc = new MyClass();
    tmc.Color = Color.Purple;
    DoSomethingWith(tmc);

    It happens so often I almost want some sort of technique to make it much easier to "chain" these temporary objects from the language side... Something like "with" on the VB-side, but perhaps as part of/connected to the new operator...
  • Anonymous
    July 13, 2004
    How do you handle UI constructs ?
    Text Boxes, labels, combo boxes ?
    I find it usefull to still use hungarian on these controls
  • Anonymous
    July 14, 2004
    We actually treat all objects the same. If the object is named correctly then you should know what it is. For Example:

    this.Enabled is an adjective so it must be boolean
    this.IsActive is a question which makes it boolean

    this.SubjectLabel would be a label.

    this.MainDataGrid would obviously be a data grid.

    I really hate having to teach my developers what the hungarian prefixes will be for these things. I think the focus needs to be on the functionality of the code not the remembering of nameing conventions.

    While the names can be long they are easily NOT typed by hitting CTL + SPACE ;)

  • Anonymous
    August 03, 2004
    If we require brief objects, say we set no or one property to a object and pass it to function.
    In this case, what is more efficient, to create new variable and pass it to mathod or create temporary object in method call.
    What will be Efficient :-
    A)
    MyClass tmc = new MyClass();
    Function1(tmc);
    B)
    Function(new MyClass());
  • Anonymous
    June 09, 2009
    PingBack from http://greenteafatburner.info/story.php?id=3848