var : A Hotbed of Extremism

Life used to be simple, however with the release of C# 3.0, Microsoft ushered into the world the birth of the implicit type keyword known as var. With this keyword, we are able to make local variable declarations without having to specify the actual type of the variable. With var, the compiler takes care of that nasty bit of business for us.

Instead of having to write the following:

// No var yet :(
int number = 10;
string message = "Hello there";

We can now write it like so:

// Hooray we have var! :)
var number = 10;
var message = "Hello there";

A good software developer will seek to reduce the redundancy in the things that they do; a proper engineer seeks to to optimize processes and increase efficiency. It’s only natural that many developers saw this new feature and recognized the boost in productivity it could offer in relation to writing code.

Declaring a local variable used to require the writer to know what exactly they were declaring. Not only that, it required the writer to have to actually write it. These things take time, so why bother with any of that when we can just simply declare all local variables as type var? Why indeed. This was the question asked by many a developer, and from this question a new form of software development extremism was born: Thou Shalt Always Use “var”.

To a very casual informer, this may appear as just another case of some guy on the internet making a very large exaggeration of things. But it really isn’t, and belief in this extreme approach is widespread. If you Google the topic, you will probably find that most people posting on Stack Overflow as well as writing their own articles subscribe to the pervasive use of var.

Most prominently, however, is the (enabled by default) inspection rule in ReSharper that will yell at you if you even think to declare a local variable using any type other than var. The keyword var, like every other feature in a programming language, is a tool that has its purpose. And, like any tool, there are times where it is sensible to use it, and many times where it is not.

I will go over the problems var causes, as well as when it should and shouldn’t be used in a bit; but first, let’s take a look at some history and ask ourselves why var even exists.

The Origins and Purpose of var

Was var added to the language because Microsoft suddenly adopted a hipster-ish attitude towards local variable types, uttering a collective PFFT towards the plebian uses of int, string, and MyClass local type declarations?

Well don’t look at me. How am I supposed to be able to read their minds? Mind reading aside, we can state definitely that the introduction of the var keyword was necessitated by the introduction of another feature into C# 3.0: Anonymous Types. With anonymous types, we are able to create types on the fly. Often we’ll create these types while in the middle of some sort of complicated LINQ query in order to aid in the filtering or projection of some sort of desired result.

Here is a very simple example:

var coolNewType = new {Id = 12, Message = "Hey Buddy!"};

int id = coolNewType.Id;
string message = coolNewType.Message;

So, what’s the type of coolNewType? If you look under the covers during runtime, you’ll see that its type is actually <>f__AnonymousType0`2. This is of course, hideous and cannot actually be expressed in our code, so we have to use var here.

This is not the only reason for the introduction of this keyword, but it is probably the primary reason. Redundant type specifications in code is of course a very large annoyance, and is indeed another reason why var was introduced into the language. At least, according to Eric Lippert, one of the big bois on the C# team at the time. Feel free to read more of his thoughts on the matter in his article “C# 3.0 is still statically typed, honest!

But what’s actually redundantly obvious vs not is very subjective, and something I hope to grant some clarity with this writing. But before we get to that, let’s get to proclaiming one of my very own dogmas.

Ready?

var Makes Code Easier to Write, But Harder to Read

The var keyword has a countless number of proselytizers that proclaim it increases code readability. But what does it mean for code to be easier to read? Does it simply refer to code being more pleasant to the eye and less “ugly”, or should it perhaps refer to the ease in which one might actually understand what the code is doing? I suspect that these advocates are of the mind that it refers to the former, and like other extremists, their beliefs have been shaped by a world view so simplified that it is unrealistic.

A few years ago, I didn’t have any strong opinions on the var keyword. My initial opinion on the matter was that it was more of a negative than a positive since it essentially hides information from the reader. But, other than that thought, I didn’t see it as too much of a bad thing really.

This all changed when I got a new job where the coding convention made rampant use of the var keyword. The software that was worked on dealt with very complex engineering concerns, with a lot of math and classes that dealt with signal transformations and the like. And I can say, with real world experience on the matter under my belt, that learning how the code worked and what it did, was made way, way more of a nightmare because of the use of the var keyword.

If you’re dealing with real world code, with real world business concerns, then you have a complex hierarchy of objects you have to deal with. This is unavoidable and anyone who pretends otherwise lives in an ivory tower, probably making their living by selling books peddled by the useless idiots barking their dogmatic truths.

Because of the rampant use of the var keyword I no longer could tell just by eyeballing the code exactly what types of data I was working with. I had to either Ctrl+Click the properties (going to their definition), or hover over the variable. This is a failure in code writing, and horrifically tedious to work with. I’ll admit, every time I was told to replace a declared variable type with var during a code review, I died a little bit inside.

Real world problems aside, I’ve recently noticed yet another shortcoming to the rampant use of var, and it has to do with a somewhat new feature to the language we’re all still probably wrapping our heads around.

Nullable Reference Types and var

With the release of C# 8.0, Microsoft has bequeathed unto us the nullable reference types feature. I’ve just started using it myself in some of my own projects, so jury is still out on this one, but I am liking what I see so far. If you’re unfamiliar with the feature, go check out the link I just provided as Microsoft will be able to explain it better than I can.

Working with this feature enabled can cause additional problems to pop up if you’re a heavy user of the var keyword. With nullable references enabled, the two following statements become an important part of the code you’ll be writing:

  • whether a reference isn’t supported to be null, and
  • whether a reference may be null

Use of the var keyword may result in communication regarding these two statements effectively being lost. As an example, let’s take a look at some code I wrote up while working with the System.Text.Json namespace:

var typePropertyName = reader.GetString();
if (typePropertyName != TypePropertyName)
{
    throw new JsonException(
        Strings.JsonInvalidTypeName.CulturedFormat(typePropertyName, TypePropertyName));
}

reader.Read();
if (reader.TokenType != JsonTokenType.Number)
    throw new JsonException(Strings.JsonTypeValueNotNumber);

var typeDescriptor = reader.GetInt32().ToEnum<TTypeDescriptor>();
reader.Read();

if (reader.TokenType != JsonTokenType.PropertyName)
    throw new JsonException(Strings.JsonMalformedText);

var dataPropertyName = reader.GetString();
if (dataPropertyName != DataPropertyName)
{
    throw new JsonException(
        Strings.JsonInvalidTypeName.CulturedFormat(dataPropertyName, DataPropertyName));
}

Some normal and seemingly harmless looking code. We see several var typed variables being declared, and the use of var would probably appear totally OK to many, as the type is obvious from the method names being invoked, right? I mean, the method invocation reader.GetString() would appear to clearly imply that it is returning a string, no? Except that it isn’t returning a string, it’s actually returning a string?.

The opportunity to make a statement that the typePropertyName and dataPropertyName variables may be null is effectively lost if we decide to use var in more ways than one. If you look back at the first link I provided to Microsoft’s documentation on the keyword, you will see a section near the top that states the following:

When var is used with nullable reference types enabled, it always implies a nullable reference type even if the expression type isn’t nullable.

Microsoft

Loss of information, loss of information, loss of information.

When Is it OK to Use var?

Please don’t just use tools blatantly people, and do as George Carlin says and learn to question what’s being fed to you. I’ve done a lot of questioning of this practice myself, and after many thoughts on the matter, I have, for your benefit, a nice guide to follow for when it makes actually makes sense to use var so that you don’t make your code a nightmare to understand.

I. When You Have To (i.e. Anonymous Types)

Yes, yes, this is a bit obvious, but I wanted this list to be complete! Of course, if you’re ever dealing with anonymous types, and you need to store a reference to one locally, then of course make sweet use of that var keyword baby!

I mean, you really don’t have any other option….but I’m just putting it out there.

II. Object Creation via the new Keyword

You’ll hear many fervent adopters of var keyword indulgence say that you should use it whenever the assignment statement makes it obvious as to what type will be returned. A measure of something’s level of obviousness is really a very subjective matter. Things that may appear to be incredibly obvious to an expert in a particular domain model can very easily be viewed as anything but obvious from a newbie’s perspective.

There’s actually only a few kinds of statements that leave no room for doubt as to the type of object being assigned. An object creation expression utilizing the new keyword is one of those.

Indeed, it is incredibly annoying to have to write something like:

List<KeyValuePair<int,string>> niceList = new List<KeyValuePair<int,string>>();

Save yourself the heartburn and relax in the comfort offered by the var keyword, as there can be no doubt whatsoever as to what is being returned.

var niceList = new List<KeyValuePair<int,string>>();

Indeed, this very specific type of redundancy reduction was stated to be one of the driving factors behind the creation of the var keyword by one of the language designers.

With C# 9.0, however, we now have target-typed new expressions. This looks like:

List<KeyValuePair<int,string>> niceList = new();

Of course this requires a default constructor, but if one is available, then you have even one less reason to use var. I mean, you still can, however you technically save a few keystrokes if you go the target-typed new expression route. Just saying.

III. Explicit Type Conversions

Another example of a statement where the type being returned is actually obvious is one where an explicit cast is used.

var options = (JsonSerializerOptions)foo;

If I scolded you for using var for a statement like the above, then you would have proof that I’m simply spouting hot air. But nay, you need not worry friend, as this type of statement makes it actually obvious as to what type is returned. So feel free to var it up.

IV. When a Generic Parameter Controls the Results

Yes, this is wading a bit into non-obvious waters, as it consists of statements not being controlled by built-in keywords, but if the return type of a method is directly controlled via a generic type parameter, then you may feel free to use var.

var obviousReader = Activator.CreateInstance<StreamReader>();

This starts to dip its toes into the territory bordering the land of obviousness, so, as with everything else, use your head.

V. When Enumerating a Local IEnumerable<T>

If we have a local variable of type of IEnumerable<T>, we can more or less be assured that the object returned from enumerating it will be of type T.

IEnumerable<Type> types = FromSomewhere();

foreach (var type in types)
{
    // Do stuff...
}

Although this too begins to dip its toes into the land of uncertainty, I feel that it’s acceptable to also use var if we’re accessing a local collection via an indexer or some other standard method. All within reason of course.

VI. When Assigning Another Local Variable or Method Parameter

If we need to declare a variable to hold a reference to another local variable or method parameter, there can be no doubt as to what that type is, so no harm in using var here as well.

IEnumerable<Type> types = FromSomewhere();

foreach (var type in types)
{
    // To prevent closures from closing over a non-local variable.
    var localType = type;

    // Do some lambda stuff.
}

And That’s It!

These are the only cases in which I’ll use the var keyword. Using it anywhere else is simply making your code harder to understand for the next person who has to read it. Making your code writing process as efficient as possible is of course important, however the readability of your code far outweighs the convenience you get from not having to type local variable types.

For real world projects with a full object hierarchy, the overuse of var will require anyone new to the project unnecessary pain, making them have to hover over everything in order to make sense of things. Don’t just take my word for it, take a look at what Microsoft does on their own source repository for .NET 5.0. I’m sure you can find some examples that counter what I’ve said, but you’ll observe an overwhelming lack of the use of var for cases that fall outside of what I listed above.

So do yourself and everyone else a favor and disable the Use preferred ‘var’ style ReSharper rule the next time you’re able to. You’ll be making the world a better place. As always, question commonly peddled advice, and try to find what those in the know do.

Thanks for reading! Hope you found this useful. Until next time.