C# – When to use the var keyword

As long as I’ve been programming with C#, there’s been a civil war. Only one subject polarises developers more than this one; tabs vs spaces anyone?

Essentially, when your app is compiled, the types of any variables declared with var are inferred by the compiler.

var myList = new List<int>();

In the above code, myList is inferred to be of type List<int>.

Generally, I don’t use var all the time, and here’s why.

Code Reviews

A common argument against using var is that you can’t see the type just by looking at it. Is this important? If you need to know the type of a variable, hovering over the var keyword shows the type, right? Look at the following piece of code. Can you tell me what type the initialisation variable is?

var initialisation = _userAccountService.PreRegister(email, password, 1);

We’re not always viewing code in the IDE; we’re viewing it in a web interface like Github, BitBucket, Kiln, or VSTS (TFS). You won’t see any tooltips or ReSharper helpers, etc. Often, knowing the type of a variable is essential to understanding the code. If you use var, the reviewer may have to pull down your changes to inspect it further. For larger reviews, yes, you should check out the code. But this is a time sink for smaller changes.

Async

The zombie virus of async is spreading. Let’s look at some more code. I happen to have prior knowledge of the GetTotalServiceCostAsync() method, and know that it returns a decimal.

var totalServiceCost = _productService.GetTotalServiceCostAsync(id);

What type is the variable in this case? Decimal? Look again. This developer has accidentally missed the await keyword, so the type is actually Task<decimal>. This line will compile, and in some cases, so will the rest of your app, in which case manifesting only as a runtime error.

This is almost the same argument of the first. The var keyword is hiding the type. I wanted to raise this as a separate principle, as with async, its a lot easier to affect the return type of the method, by simply forgetting a keyword. Would it be better written as the following?

decimal totalServiceCost = _productService.GetTotalServiceCostAsync(id);

This line will not compile, and will shout at the developer in the IDE with a big red squiggle. This situation is even cloudier when async methods are used which don’t follow the accepted naming convention, ending with the word ‘Async’. So whenever it’s not clear from the assignment what the type is, I use the intended type rather than var.

Refactoring

Another argument for using the var keyword is that it eases refactoring. The idea here is that you can change a return type, and then not have to change as much code wherever the method is used. This speeds up refactoring. This is usually quite a divided opinion point. I agree that it can speed up refactoring, but I don’t think that’s a good thing.

Consider this contrived example.



public ActionResult Result()
{
    var returnValue = GetResult();

    return View(returnValue);
}

private bool GetResult()
{
    return true;
}


Let’s say that we realise that passing a bool to a view isn’t that great, and want to pass a concrete type instead.



public ActionResult Result()
{
    var returnValue = GetResult();

    return View(returnValue);
}

private Result GetResult()
{
    return new Result { Success = true };
}


Note how in this case we don’t need to touch the Result() action method at all because of the var keyword. Compile-time type inference will produce different compiled code to handle the new return type. The View() method accepts an object, so this change won’t cause any compile time errors. At runtime however, the Result page will likely die and turn yellow. A good developer will try to check every code avenue during refactoring, or even write passing unit tests first. But even a brilliant developer may miss something, especially in complex applications. Would it be better if everywhere the return value of GetResult() is used, it started failing at compile-time? Often that would be better, as it forces us to ensure that our type change works everywhere. So, in the example above, using decimal instead of var is preferable.

When Then?

Despite the above points, there are lots of situations where var is preferable, and some where it’s essential!

Single-line Declaration and Assignment

You can use var to make your code more succinct. For some, the first line is more readable than the second.


var provider = new CachingUserManagementSessionProvider();

CachingUserManagementSessionProvider provider = new CachingUserManagementSessionProvider();

I think there’s a more subtle reason than readability to use var here. Even though we are being less verbose, we are also only specifying the type once in code, therefore being more explicit about the type declaration. Since the declaration and assignment happens on the same line, we can safely assume that the type specified on the right is the one the developer intended to use.

The exception to this is when you are deliberately assigning to a base type variable, for instance…


UserManagementSessionProvider provider = new CachingUserManagementSessionProvider();

Anonymous Types

Just a quick shoutout to the big advantage of var.


var quickie = new { Result = true };

Console.WriteLine(quickie.Result);

Here we get a strongly-typed anonymous object with properties we can access directly in code.

In summary, var is great for keeping your code succinct and readable, but overuse can have the opposite effect.

Thanks for reading.

One thought on “C# – When to use the var keyword

Add yours

  1. With the “_userAccountService.PreRegister” example, *is* the type important to the review? Does it matter if it’s an IUser or a UserAccount or an UnverifiedUserAccount? If the code that uses the “initialisation” references has logic that to be appears correct and the code is compiling then it seems reasonable that the returned type is appropriate, regardless of what it actually is. If the review process is performed entirely in a web UI then presumably there is an automated build / test-running process happing as well that ensures that the code builds and that the visual review really is just to ensure that the logic is correct?

    With regards to refactoring, if I call a method and really only care that I get an ordered list of T then it shouldn’t really matter if it returns List or T[]. And if the method returns List but then gets refactored to return T[] then that change shouldn’t require me to change the code that calls it. I often see people, when they don’t want to use var, declaring a reference to be the concrete type that the method currently returns, rather than the type that they’re really interested in. In this example, if I want to avoid var then I should say something like “IEnumerable x = GetItems();” because that won’t need changing if “GetItems” is changed to return T[] instead of List (and it more accurately describes the requirements of the code – I want an enumerable list of T; I don’t need to add to or remove from it, I don’t need to mutate its contents, etc). If you specify what type you really need (such as IEnumerable) then some of the ease-of-refactoring benefits from using var are diminished. It’s worth noting, while talking about refactoring, that type inference *can* break down when you’re working with code that plays fast and loose with types – MVC Views, as you point out, are an excellent example of this. However, I think that it suggests that the guideline should be to be careful with type specifications when dealing code that is not strongly typed (which tends to be the exception in C#, rather than the rule – if I was working with dynamic references then I might also be tempted to be more explicit about variable type declarations) rather than saying the var is dangerous in general.

    Another consideration is LINQ methods (or any chaining “fluent” API). If you call “_productService.GetItems(orderId).GroupByManufacturer(item => item.Manufacturer.Name).OrderBy(group => group.Key);” would you be happy to assign that using “var”? Are you worried that, even if you don’t use var there, that you can’t see the types returned by either “GetItems” or “GroupByManufacturer”? If you *do* use var then you don’t know (or care?) what type OrderBy returns – is that something you’re worried about (and if not, why not)?

    I presume that you refer to async as “a zombie virus” because it has a tendency to spread quickly through code (as is recommended by “Async all the way” in https://msdn.microsoft.com/en-us/magazine/jj991977.aspx), rather than because it’s evil and wants to eat your brains. This point made me think. While async isn’t very new any more it’s also not something that everyone uses days to day or has a perfect grasp on. And the “Async” method suffix is not always used consistently (though MS explicitly recommend it; “Asynchronous methods in TAP [Task-based Async Pattern] include the Async suffix after the operation name” – see https://msdn.microsoft.com/en-us/library/hh873175.aspx). There could be an argument for being more explicit with types here, particularly if working with less experienced developers. I’m dubious that it’s easy to write compiling code that requires the result of an async method and that doesn’t await it – as soon as you try to perform an operation that requires a decimal and you provide it with a Task then it’s going to fail to compile. I’m struggling to imagine how it could manifest as a runtime failure (with the possible exception of the result being passed to loosely-typed code again; like to an MVC View or a dynamic reference). I also suspect that you can could catch more mistakes around async with tooling – the compiler produces helpful warnings around misuses of async and enabling treat-warnings-as-errors in the build process could mean that fewer mistakes make their way through to the manual review process (even if you use var).

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Create a website or blog at WordPress.com

Up ↑

%d bloggers like this: