views:

900

answers:

18

Our internal audit suggests us to use explicit variable type declaration instead of using the keyword var. They argue that using of var "may lead to unexpected results in some cases".

I am not aware of any difference between explicit type declaration and using of var once the code is compiled to MSIL.

The auditor is a respected professional so I cannot simply refuse such a suggestion.

+1  A: 

I follow a simple principle when it comes to using the var keyword. If you know the type beforehand, don't use var. In most cases, I use var with linq as I might want to return an anonymous type.

PieterG
But is it realy bad to use var keyword "everywhere"?
x2
It's a matter of personal preference. Having `var` for _everything_ might make it hard to work out what's going on without using intellisense everywhere.
thecoop
+9  A: 

var is not a dynamic type, it is simply syntactic sugar. The only exception to this is with Anonymous types. From the Microsoft Docs

In many cases the use of var is optional and is just a syntactic convenience. However, when a variable is initialized with an anonymous type you must declare the variable as var if you need to access the properties of the object at a later point.

There is no difference once compiled to IL unless you have explicitly defined the type as different to the one which would be implied (although I can't think of why you would). The compiler will not let you change the type of a variable declared with var at any point.

From the Microsoft documentation (again)

An implicitly typed local variable is strongly typed just as if you had declared the type yourself, but the compiler determines the type

In some cases var can impeed readability. More Microsoft docs state:

The use of var does have at least the potential to make your code more difficult to understand for other developers. For that reason, the C# documentation generally uses var only when it is required.

badbod99
-1, there *can* be differences in the IL generated.
0xA3
@0xA3 could You add some more details on that?
Arnis L.
@0xA3 - Yes, please elaborate.
ChaosPandion
There's no difference in the IL than if you explicitly declared the same type that is being inferred with var. If you actually wanted a *different* type than the one inferred, then yes there are differences.
Tim Goodman
0xA3 - That is a cheap shot if you are referring to what Tim points out, as that is clearly nothing to do with this question.
badbod99
A: 

using var is lazy code if you know what the type is going to be. Its just easier and cleaner to read. When looking at lots and lots of code, easier and cleaner is always better

Spooks
I disagree with this point. I don't think you save all that much by explicitly giving the type. In most cases you will be looking at what goes into the variable anywho, not just looking at the name and type.
Adkins
i'm talking about at glance though, easier on the eyes, which makes it easier to read, though maybe this is just personal preference
Spooks
@Spooks: This whole question (IMHO) boils down to personal preference. The Auditor is obviously not a fan of var so he recommends to every to avoid it. If another Auditor goes through the company from OP tomorrow could be the complete opposite. Something this trivial is nothing more than preference.
Adkins
@Adkins this is true, business logic should be put into place so everyone follows the same guidelines.
Spooks
+4  A: 

They argue that using of var "may lead to unexpected results in some cases".to unexpected results in some cases".

If unexpected is, "I don't know how to read the code and figure out what it is doing," then yes, it may lead to unexpected results. The compiler has to know what type to make the variable based on the code written around the variable.

The var keyword is a compile time feature. The compiler will put in the appropriate type for the declaration. This is why you can't do things like:

var my_variable = null
or
var my_variable;

The var keyword is great because, you have to define less information in the code itself. The compiler figures out what it is supposed to do for you. It's almost like always programming to an interface when you use it (where the interface methods and properties are defined by what you use within the declaration space of the variable defined by var). If the type of a variable needs to change(within reason of course), you don't need to worry about changing the variable declaration, the compiler handles this for you. This may sound like a trivial matter, but what happens if you have to change the return value in a function, and that function is used all throughout the program. If you didn't use var, then you have to find and replace every place that variable is called. With the var keyword, you don't need to worry about that.

Kevin
+10  A: 

Some cases could really lead to unexpected results. I'm a var fan myself, but this could go wrong:

var myDouble = 2;
var myHalf = 1 / myDouble;

Obviously this is a mistake and not an "unexpected result". But it is a gotcha...

Daren Thomas
If this is truly what the auditor was referring too and he is a respected professional, then he should have seriously reworded his recommendation...
Adkins
A: 

There is absolutely no difference in the IL output for a variable declaration using var and one explicitly specified (you can prove this using reflector). I generally only use var for long nested generic types, foreach loops and anonymous types, as I like to have everything explicitly specified. Others may have different preferences.

thecoop
No, see my answer for an example where this is not the case.
0xA3
I would say it _is_ the case, your example is just an artefact of a C# 1 feature (implicit `foreach` casting) interacting in an unexpected way with the C# 3 `var` - if the element type was `object` you would get exactly the same IL as `var`
thecoop
In your example, there's a difference because the inferred type is not the one you really wanted. But if you explicitly declared `node` to be of type `object` (i.e., if the inferred type *was* the one you wanted), there'd be no difference.
Tim Goodman
@thecoop: Implicit foreach-casting still happens in C# 4.0, what is different is that the enumerator is strongly typed when you are using `foreach` with an `IEnumerable<T>`.
0xA3
+16  A: 

I tend to follow this scheme:

var myObject = new MyObject(); // OK as the type is clear

var myObject = otherObject.SomeMethod(); // Bad as the return type is not clear

If the return type of SomeMethod ever changes then this code will still compile. In the best case you get compile errors further along, but in the worst case (depending on how myObject is used) you might not. What you will probably get in that case is run-time errors which could be very hard to track down.

ChrisF
We got intellisense to show us what the return type is. And the method itself should make it obvious of what it returns.
Claus Jørgensen
@Claus - you don't always want to hover over the `var` to see what type it is and method names don't always meet the ideal standard.
ChrisF
@Claus: but it is easier when you can just look at the declaration and know, instead of having to actively acquire it
Oren A
@Oren You should know context in which class, method You are. Once You know it, it's just wasting time telling compiler that apple is an apple. Even worse - it already knows that.
Arnis L.
@Arnis L: even when fixing a bug in a 10,000 line source file that you haven't had to look at before?
thecoop
@thecoop see? it's not problem with `var`, but with Your code! :)
Arnis L.
Arnis L: That's just arrogant. Everyone has legacy code they would like to rewrite but can't because of time constraints. And you shouldn't booby-trap the code for anyone else fixing bugs in the same file later on.
thecoop
Readability is not anything to do with unexpected results (well it could be).
badbod99
@thecoop I wouldn't just replace everything to var. I would refactor those 10k lines into small, encapsulated pieces and then - replace everything to var. Otherwise - I wouldn't touch it at all. Especially, if it's untested.
Arnis L.
@Claus: In code review situations, code listings are often used - intellisense does not work in dead tree ;)
Daren Thomas
I agree with the example ChrisF has written - var should only be used when its absolutely clear what kind of variable the "var" is.. Ive seen too much code where var is used for everything and it makes it very hard to maintain..
femseks
@badbod99 readability has a lot to do with expected results. Organizations that have a second person review code usually do this by having them "read" the code. I do the reading with the help of the IDE, intellisense, and writing proof-of-concept if necessasry. It is most helpful for code reviews if the programmer's intent is clear (or approaches clear, reviewers still have their work to do).
Les
A: 

var is just a shorthand notation of using the explicit type declaration.

You can only use var in certain circumstances; You'll have to initialize the variable at declaration time when using var. You cannot assign a variable that is of another type afterwards to the variable.

It seems to me that many people tend to confuse the 'var' keyword with the 'Variant' datatype in VB6 .

Frederik Gheysels
A: 

The "only" benefit that i see towards using explicit variable declaration, is with well choosen typenames you state the intent of your piece of code much clearer (which is more important than anything else imo). The var keyword's benefit really is what Pieter said.

MrDosu
+4  A: 

When coming up with guidelines, as an auditor has to do, it is probably better to err on the side of fool safe, that is white listing good practices / black listing bad practices as opposed to telling people to simply be sensible and do the right thing based on an assessment of the situation at hand.

If you just say "don't use var anywhere in code", you get rid of a lot of ambiguity in the coding guidelines. This should make code look & feel more standardized without having to solve the question of when to do this and when to do that.

I personally love var. I use it for all local variables. All the time. If the resulting type is not clear, then this is not an issue with var, but an issue with the (naming of) methods used to initialize a variable...

Daren Thomas
I would have to say a good compromise would be using `var` for something like this: `IDictionary<string, MyVeryLongGenericClassName<int, string, DateTime>>`
ChaosPandion
+8  A: 

In the non-generic world you might get different behavior when using var instead of the type whenever an implicit conversion would occur, e.g. within a foreach loop.

In the example below, an implicit conversion from object to XmlNode takes place (the non-generic IEnumerator interface only returns object). If you simply replace the explicit declaration of the loop variable with the var keyword, this implicit conversion no longer takes place:

using System;
using System.Xml;

class Program
{
    static void Foo(object o)
    {
        Console.WriteLine("object overload");
    }

    static void Foo(XmlNode node)
    {
        Console.WriteLine("XmlNode overload");
    }

    static void Main(string[] args)
    {
        XmlDocument doc = new XmlDocument();
        doc.LoadXml("<root><child/></root>");

        foreach (XmlNode node in doc.DocumentElement.ChildNodes)
        {
            Foo(node);
        }

        foreach (var node in doc.DocumentElement.ChildNodes)
        {
            // oops! node is now of type object!
            Foo(node);
        }
    }
}

The result is that this code actually produces different outputs depending on whether you used var or an explicit type. With var the Foo(object) overload will be executed, otherwise the Foo(XmlNode) overload will be. The output of the above program therefore is:

XmlNode overload
object overload

Note that this behavior is perfectly according to the C# language specification. The only problem is that var infers a different type (object) than you would expect and that this inference is not obvious from looking at the code.

I did not add the IL to keep it short. But if you want you can have a look with ildasm to see that the compiler actually generates different IL instructions for the two foreach loops.

0xA3
I always use var when I write foreach statements and have never had the problem you are describing...
Adkins
@Adkins: As long as you are using the generic `IEnumerable<T>` interface you won't see this issue as no implicit conversion takes place and the compiler will resolve the type of the variable declared with `var` to `T`.
0xA3
I prefer `System.Xml.Linq` anyway.
ChaosPandion
@0xA3: I also do foreach(var element in doc.depenedent("blah").Attributes()) or something like that. Maybe I am not understanding what you are saying properly. From my understanding and limited experience both should work as doc.DocumentElement.ChildNodes returns a definitive type.
Adkins
@ChaosPandion: It might not always be your choice to use Linq e.g. if your interface requires an `XmlDocument`. Also `XmlDocument` was just an example, there is still lots of non-generic code around (like almost all of Windows Forms) where you will run into the issue decribed in my answer.
0xA3
@Adkins: That definitive type is `object` if you are enumerating an `IEnumerator`. I have experienced this problem as well. Another solution would be to add `.Cast<YourType>()`, but it seems more straightforward to just specify the type.
recursive
It just infers type You didn't expect. IL still is the same. Try harder.
Arnis L.
I would say the problem with the update is the naming of the methods rather than the usage of var. Having 2 methods with the same name that produce different output like that and only vary based on the input value leaves a bad taste in my mouth.
Adkins
@Adkins: This is called method overloading and one of the very basic features of C#. Check out the base class library and see that it is a heavily used core feature. It prevents you from having a gazillion of different method names that only vary by type. See e.g. the many different `Convert.ToString()` overloads.
0xA3
@Arnis L.: Sure, the `var` feature is not broken. But the point is that infering an unexpected type here is not obvious at all and it is probably the reason that the auditor suggested to prefer explicit variable declaration.
0xA3
This is because IEnumerator returns type of Object rather than T in it's Current property (as used in foreach). Nothing really to do with var, you would have the same result with (object node in ...
badbod99
Point is that it's not really unexpected behaviour, just another case of var readability (or lack of).
badbod99
@0xA3: well I feel like an @$$ now :P That is a very true. I am not even sure what I was thinking anymore! Is it really proper though to say never use var simply because of this instance where it does not do as expected though? Wouldn't it be better to warn about this case?
Adkins
@Adkins - The example is a bit contrived though.
ChaosPandion
@ChaosPandion: Simple examples always look contrived. Replace the `Foo` method with e.g. a serialization method `Serialize(Stream s, XmlNode node)` or `Serialize(Stream s, object o)` respectively and it probably will make more sense.
0xA3
Of course, the interesting thing here is that it's the `var` declaration that does what you expect and the explicit type declaration that does not. When using `var` you have to manually cast, whereas with the explicit type declaration the compiler inserts the cast for you. When you get the code wrong and get an `InvalidCastException` the code that uses `var` will be much more obvious to debug to find out why it's doing that, because you wrote the cast, whereas with the explicit type declaration you'd have to have to know the compiler inserted it for you.
Greg Beech
+31  A: 

How about this...

double GetTheNumber()
{
    // get the important number from somewhere
}

And then elsewhere...

var theNumber = GetTheNumber();
DoSomethingImportant(theNumber / 5);

And then, at some point in the future, somebody notices that GetTheNumber only ever returns whole numbers so refactors it to return int rather than double.

Bang! No compiler errors and you start seeing unexpected results, because what was previously floating-point arithmetic has now become integer arithmetic without anybody noticing.

Having said that, this sort of thing should be caught by your unit tests etc, but it's still a potential gotcha.

LukeH
If it only ever returns whole numbers, exactly what code could you write which would return unexpected results?
badbod99
@badbod99: Use your imagination! Trivial example: Consider `Console.WriteLine("97 divided by 5 is " + (97 / 5));` versus `Console.WriteLine("97 divided by 5 is " + ((double)97 / 5));`.
LukeH
@badbod99: Would you be happy if your salary was inadvertantly rounded down because some floating-point arithmetic became integer arithmetic without anybody noticing?
LukeH
I guess `theNumber / 5` would not always result in a whole number in that case, but since `theNumber` suddenly is an integer, the division is done using integer logic as well.
deltreme
I guess this one of the reasons why it's good to have different operators for (floating point) division and integer division just like Pascal has, i.e. `/` and `div`.
Cristian Ciupitu
Not questioning the fact, purely requesting an example in your answer :-) Peronally if I was doing maths like that and expected a double result, I would always explicitly cast (to make bl**dy sure)
badbod99
Thing is - this is NOT fault of `var` keyword. It's fault of `curvedHands.dll`.
Arnis L.
@LukeH - Interestingly, however, in this example you're quite happily relying on the compiler to infer that the written value 5 (an `int` declaration) should be interpreted as 5.0 (a `double` value). Also, given that in 'real' production code the constant would never be declared inline like this, but as an actual constant of type `double`, because presumably the meaning of the constant is significant, then the actual semantics of the code would be unchanged. In addition, tools like ReSharper warn about "Possible loss of fraction.". I think this is a non-issue in well written real-world code.
Greg Beech
@Greg: I agree completely. As you say, this should be a non-issue in "well written" code, but that's the crux of the problem: These types of gotcha rarely crop up in well written code; it's always the badly written, badly understood code that bites you.
LukeH
@Greg ReSharper's default suggestion is to change declerations to `var`. So what could happen is you make the change the signature of that method to an `int`, in a different file, and nobody looks at the usages and the warning is never seen. Now if it was a VS warning, it might be more helpful. But with the number of ASP.NET warnings, that system isn't the greatest.
Yuriy Faktorovich
+5  A: 

It's an odd claim that using var should never be used because it "may lead to unexpected results in some cases", because there are subtleties in the C# language far more complex than the use of var.

One of these is the implementation details of anonymous methods which can lead to the R# warning "Access to modified closure" and behaviour that is very much not what you might expect from looking at the code. Unlike var which can be explained in a couple of sentences, this behaviour takes three long blog posts which include the output of a disassembler to explain fully:

Does this mean that you also shouldn't use anonymous methods (i.e. delegates, lambdas) and the libraries that rely on them such as Linq or ParallelFX just because in certain odd circumstances the behaviour might not be what you expect?

Of course not.

It means that you need to understand the language you're writing in, know its limitations and edge cases, and test that things work as you expect them to. Excluding language features on the basis that they "may lead to unexpected results in some cases" would mean that you were left with very few language features to use.

If they really want to argue the toss, ask them to demonstrate that a number of your bugs can be directly attributed to use of var and that explicit type declaration would have prevented them. I doubt you'll hear back from them soon.

Greg Beech
+1 for "If they really want to argue the toss, ask them to demonstrate that a number of your bugs can be directly attributed to use of var and that explicit type declaration would have prevented them. I doubt you'll hear back from them soon."
Jeroen Pluimers
A: 

Readability

ste
A: 

var best using when you have obviously declaration

ArrayList<Entity> en = new ArrayList<Enity>()

complicates readability

var en = new ArrayList<Entity>()

Lazy, clear code, i like it

Jeje
A: 

I also think that you will run into trouble if you declare your doubles without the D on the end. when you compile the release version, your compiler will likely strip off the double and make them a float to save space since it will not consider your precision.

Alex
A: 

I use var only where it is clear what type the variable is, or where it is no need to know the type at all (e.g. GetPerson() should return Person, Person_Class, etc.).

I do not use var for primitive types, enum, and string. I also do not use it for value type, because value type will be copied by assignment so the type of variable should be declared explicitly.

About your auditor comments, I would say that adding more lines of code as we have been doing everyday also "lead to unexpected results in some cases". This argument validity has already proven by those bugs we created, therefore I would suggest freezing the code base forever to prevent that.

tia
A: 

var will compile to the same thing as the Static Type that could be specified. It just removes the need to be explicit with that Type in your code. It is not a dynamic type and does not/can not change at runtime. I find it very useful to use in foreach loops.

foreach(var item in items)
{
item.name = ______;
}

When working with Enumerations some times a specific type is unknown of time consuming to lookup. The use of var instead of the Static Type will yeald the same result. I have also found that the use of var lends it self to easier refactoring. When a Enumeration of a different type is used the foreach will not need to be updated.

JohnEgbert