views:

145

answers:

5

Ok, I've been reading everything I can find on var, and I'm pretty sure I've got a handle on their basic behaviors and type inference. I've always been a big proponent of explicit types, so var makes me a little edgy when I'm reading code. So I have a couple of questions regarding its memory usage and the behavior of a variable declared with var over the course of that variable's lifecycle in memory.

Since var is an inference to an explicit or anonymous type, will its memory be allocated in the same place its corresponding type would be or is var universally created on the heap and accessed as if it were an object. As an example:

int i = 5;  // puts this on the stack
var i = 5;  // does this also go on the stack?

Does a declared var have a constant type once it is initialized or can it be adjusted as well? I ask this because I can't find in the documentation that specifies this, and I just read something in this SO question by @Eric Lippert:

a variable is a storage location whose contents change

Having tested the following code, I see an implicit conversion exception even at the IDE level. I don't have the experience with LINQ at this point to run a similar test with respect to anonymous types. Do they follow this same behavior? Will the IDE recognize a type mismatch at design time or would such code receive a run-time exception?

var i = 5;    // Initializes as int, value is 5
i = "Steve";  // Type casting error

Finally, is there ever a situation that you can think of where you may know a type at design time but it would be prudent to use var anyway? I ask because I've seen code samples where people do this, and from what I've read it strikes me as just lazy-coding.

EDIT: I realize there are a lot of articles talking about this topic, but I haven't found any that answer these questions specifically (though some hint one way or another). I would be happy to read any document you feel is relevant to these topics, just please post a link.

+15  A: 

var is 100% syntactic sugar in the C# compiler. When the actual IL is generated, the type is explicitly defined. var-declared variables do not behave any differently from their explicitly-defined counterparts. The dearth of information you're seeing is coming from the fact that var is simpler than you're assuming. There is quite literally no difference between these two lines:

var i = 10;
int j = 10;

(Other than the fact that you see the words var and int, of course; they are functionally completely identical).

Adam Robinson
@Adam - so by that rationale, if I were to diagram out anonymous types as if they had explicit names like X, Y, Z, I should reasonably be able to track how they will behave and where their memory should be allocated?
Joel Etherton
@Joel - no, you can't, but that's becuase .Net uses managed memory and so you can't track where memory is allocated anyway. The important thing to know is the `int i = 10;` and `var i = 10;` compile to _the exact same IL_.
Joel Coehoorn
@Joel Etherton: @Joel Coehoorn is right; you can't do that with anonymous types, but you also can't do it with any other type. If by "where" you mean stack vs. heap, then all anonymous types are on the heap, as all anonymous types are reference types. It's not really something terribly relevant, though, as all instances of an anonymous type will fall out of scope no later than the end of the method in which they're declared, since you cannot expose an anonymous type outside of its declaring method.
Adam Robinson
@Adam, @Joel Coehoorn: Thanks. my statement really was more of me just trying to wrap my brain around the concept.
Joel Etherton
@Adam: The fact that an anonymous type cannot be directly exposed in the return type of a method at compile time has nothing whatsoever to do with the lifetime of an instance! A method is free to return object, and that object can be an instance of an anonymous type.
Eric Lippert
@Eric: That's true, I hadn't considered returning the instance as an `object`.
Adam Robinson
Or, you can extend the lifetime of an instance of anonymous type by capturing a local variable of anonymous type in a lambda, and then passing out the delegate. That way you can effectively make a field of anonymous type, since hoisted local variables are implemented as fields.
Eric Lippert
+8  A: 

var variables are infered by the compiler, they are really just syntactical sugar, there is no difference between:

var i =0;

and

int i = 0;

in the compiled code.

They were add for the purpose of allowing anonymous types, e.g.

var MyVar = new { prop1="A string", prop2=5};

I personally think any other use of var is bad programming.

Yes anonymous varables recognise a type mistmatch at compile time, the compiler dynamically creates a class for them when it compiles. e.g. the below would not compile:

var MyVar = new { prop1="A string", prop2=5};
MyVar = "Fred";
Ben Robinson
+3  A: 

Simple answer: exactly the same as normal variables.

var declarations are translated into specific (strong) types at compile-timee. var is simply a method of automatic type inference, and has nothing to do with dynamic languages. At the end of the day, it's just the compiler being clever and translating var into what actual type you want.

Noldorin
+4  A: 

As others have said, var has no effect on how the variables behave in terms of memory - it just means you don't specify the name. For anonymous types you couldn't specify the name, first because you don't know it at compile time, and second because the names are deliberately "unspeakable" - they're not valid in C#. (Generally they contain <> for example.)

The IL generated for code using var and code using an explicit name is exactly the same. Just as a normal variable can't change type, nor can a variable declared using var... so in your example where you try to assign the value "Steve" to a variable which has an implicit type of int, you'll get a compile-time error exactly as if you'd explicitly declared it to be of type int.

As for when to use var and when not to, I have a few rules of thumb:

  • Obviously if you want the variable to have a type other than the compile-time type of the assigned expression, you've got to do it explicitly
  • For constructor calls, it's always clear what the the type is even if you're using var
  • var is useful for emphasizing what the code is meant to do rather than how
  • Often I use var if the explicit name would be extremely long - particularly for generics with multiple type arguments.

Basically it's all about readability: if the code is easier to read using var, go for it. If not, don't. Note that this isn't the same as saving typing... code is generally read more than it's written, so think about your reader. Eric Lippert wrote a great note when tech reviewing the first edition of C# in Depth, which is worth a read.

Jon Skeet
@Jon - I'm not sure I understand what you mean when you say var is useful for emphasizing what the code is meant to do rather than how.
Joel Etherton
@Joel: Read Eric's note, linked in the last sentence - as ever, Eric puts things better than I do.
Jon Skeet
@Jon - Ok, thanks. That does make it a little more clearer.
Joel Etherton
+1  A: 

"Since var is an inference to an explicit or anonymous type, will its memory be allocated in the same place its corresponding type would be or is var universally created on the heap and accessed as if it were an object"

The important thing about var, is that the compiler changes the var statement to the actual type at compile time, so:

var number = 1;

Will get changed to:

System.Int32 number = 1;

...by the compiler. And as such the memory locations for storage of these types is no different. var is essentially syntactic sugar. So, method local declarations of value types will get stored on the stack, reference pointers will get stored on the stack with the referenced objects on the heap.

Once you have declared a variable as var, because this is translated into its full type by the compiler, you can't then dynamically change the type:

var i = 5;
i = "Steve"; 

...is invalid, because its already been declared as an Int32.

Anonymous types follow a similar behaviour, where a type is created by the compiler during compilation.

"Finally, is there ever a situation that you can think of where you may know a type at design time but it would be prudent to use var anyway?"

Personally, I follow a simple pattern:

For primitives, I always put the type:

int i = 5;
string name = "Matt";

For complex types, I mostly do this:

var instance = new MyComplexTypeInstance();

For LINQ results, I stick to var:

var result = from i in something select i;

For methods, if the method is descriptive of the type being returned, then I will use var.

var instance = GetInstance();

Whereas, more complex method names, I'd put the actual type:

Result result = DoSomethingWeirdAndWonderful(); 

Each developer will find something they are comfortable with, the choice is yours. As var is only really a design-time thing, its all syntactic sugar.

Matthew Abbott