Stefan Rusek | Using ‘var’ to become a better programmer

Using ‘var’ to become a better programmer

Tuesday, March 03, 2009

When C# 3 first came out, there were a number articles written about using ‘var’ vs. explicitly typed variables. Some notable people said to use types, some notable people said to use ‘var’, and others took a pragmatic stance somewhere in the middle. In case you missed all this, here is an example:

List<int> l1 = new List<int>();
var l2 = new List<int>();

System.Web.HttpContext context1 = System.Web.HttpContext.Current;
HttpContext context2 = HttpContext.Current;
var context3 = System.Web.HttpContext.Current;

In the code above, l1 and l2 have the same types, but l2’s type is inferred from the declaration. For the declaration of l1 we specify the type twice, while in the case of l2, we don’t have to repeat ourselves. In the case of context1, we might be tempted to add a ‘using’ statement so we can use a declaration like context2, but using ‘var’ for context3 gives us a way to get the length of context2, but without polluting our global namespace. After a lot of thought and coding both ways, I have fallen into the “always use ‘var’ (except when you just can’t)” camp, because writing easily readable code as a whole outweighs the cost of possibly writing a bad assignment statement.

Much of the debate between these two methods focuses on readability of the assignment statement itself. Duplicating the type name tends to make the line harder to read, but some argue that the line is harder to read when the type does not appear on the line at all.

My contention is that the person reading the code does not actually care to know the exact type of the variable. The reader really wants to know the logical type of the variable. In every language, variables have a logical type and an exact type. The logical type is the idea that the exact type tries to represent in memory. So in other words, if you saw a call to a method CountItems(), you would know that it returned an integer, but wouldn’t really care whether it returned an int, uint, long, etc. In fact, many times uint or long make a lot more sense for the result from a method that returns the number of things. In these cases, the logical type of the variable is completely obvious, but the exact type is not. Likewise, if you had a method named GetDeletedItems(), you would know that it returned some kind of list. Many times, it does not make a lot of difference what type of list it returns, as long as you can do ‘foreach’ on it.

string Message()
{
    var items = CountItems();
    if (items == 1)
        return "1 item";
    return items + " items";
}

string ItemsToJSON()
{
    var items = GetItems();
    var sb = new StringBuilder();
    foreach (var item in items)
    {
        if (sb.Length != 0) sb.Append(",");
        sb.Append(item.ToJSON());
    }
    return "[" + sb + "]";
}

GetItems() could return an ArrayList, List<Item>, IEnumerable, or some user-defined type. We simply don’t care. The only inportant fact about GetItems() is that it returns a bunch of items we can use with the ‘foreach’ statement. In both of the above methods we have a variable named items. In both contexts, we know the logical type of the variable, but not the exact type of variable. Two things that reveal this information to us: the methods CountItems() and GetItems(), and the way we use the variables, both tell us the logical type.

You may be asking yourself how this can make you a  better programmer. Well, when a variable’s logical type is not clear, changing  the ‘var’ to an explicit type will not fix the underlying problem with the code, because it will only make the exact type clear. The real problem with the code is one or  more of the following: a bad variable name, a bad method name, or the variable  is declared too far from where it is used.

A good variable name goes a long way toward making good code. It doesn’t have to make the exact type clear to the user, but it should be clear from the context what the logical type is. Good method names are even more important than good variable names. This is because many times the consumer does not have access to the source code of the method, and even when you do have access to the method’s source it can be a pain to look at the source in order to figure out what it does. It is not uncommon for a variable declaration to get separated from where it is used as code evolves. This is something that can easily be fixed, and can dramatically improve readability.

When I worked at Fog Creek, we had a naming convention for variables that completely took a different approach to solving the problem:

Dim ixUser = GetUserId()
Dim ixUser As Int32 = GetUserId()

Dim cUsers = CountAdminUsers()
Dim rgUers = GetAdminUsers()

The ix prefix says that it is a Int32 index column from the database, thus the “As Int32” in the second line is completely redundant. The c and rg prefixes are count and array, both of which imply a type as well. The emphasis was on the logical type instead of the exact type. It was not uncommon for ixUser to actually be a string representation of an integer.

In the majority of cases the actual type just does not mater. In fact, when we let go of the exact and embrace the logical type, we will end up writing cleaner more consistent code.


Please log in or register to comment.