04 March 2008

Varification -- Using Implicitly Typed Locals

With the ReSharper 4 nightly builds available, some people are complaining about numerious suggestions to convert explicit type to "var" keyword. Of course, you can hide this suggestion by using Options / Code Inspection / Inspection Severity, or by using Alt-Enter and selecting "Change severity" option. But what's the deal with implicitly typed locals, anyway? Using var keyword can significantly improve your code, not just save you some typing. However, it may require discipline to apply good practices when using implicitly typed variables. Here is my list:


  • It is required to express variables of anonymous type. This is pretty obvious - you cannot declare local variable of anonymous type without using var.

  • It induces better naming for local variables. When you read local variable declaration with explicit type, you have more information at that moment and something like "IUnitTestElement current" makes sense. However, when this local variable is used later, you read "current" which takes some time to figure out the meaning. Using "var currentElement" makes it easier to read at any place.

  • It induces better API. When you let compiler deduce type from method return type or property type, you have to have good types in the first place. When you don't have explicit type in the initialization expression, you have to have best names for members.

  • It induces variable initialization. It is generally a good practice to initialize variable in the declaration, and compiler needs initializer to infer type for local variable declared with "var" keyword.

  • It removes code noise. There are a lot of cases, when implicitly typed local will reduce amount of text developer needs to read, or rather skip. Declaring local variable from new object expression or cast expression requires specifying type twice, if we don't use "var". With generics it can lead to a lot of otherwise redundant code. Another example would be iteration variable in foreach over Dictionary<TKey,TValue>.

  • It doesn't require using directive. With var, you don't have explicit reference to type, as compiler infers type for you, so you don't need to import namespace when you need a temporary variable.



To summarize the list above, by actively using var keyword and refactoring your code as needed you improve the way your code speaks for itself.

PS: Visit ReSharper at Visual Studio Gallery!

52 comments:

Alexander said...

C# Reference recommend to use var only in case of anonymous type.

“Overuse of var can make source code less readable for others. It is recommended to use var only when it is necessary, that is, when the variable will be used to store an anonymous type or a collection of anonymous types.”

http://msdn2.microsoft.com/en-us/library/bb383973.aspx

Ilya Ryzhenkov said...

Yeah, Microsoft often tries to make things "safer". I don't agree with them here :)

Anonymous said...

Ilya -

For all the times I've agreed with you, this time I'm not convinced. The argument that it forces better naming conventions just doesn't work for me. I want good naming conventions from my developers whether or not var is involved (and Resharper really helps with make that easy!).

Other than for the obvious use with anonymous types, which the use of var can help highlight, and the perhaps simple variable initialization:

var name = "Ilya";

or

var currentIndex = 1;

I'm not sure I favor it. When I see:

var latestUpdate = GetLatest():

it doesn't tell me what latestUpdate returns.

I'm just moving projects to 3.0 so I'm keeping an open mind on this. I'm wondering if you are considering allowing configuration of the var suggestion only in the case of simple initialization?

Thanks for sharing your thoughts on this - jlo

Ilya Ryzhenkov said...

Jeff,

var latestUpdate = GetLatest();

is quite good example of "It induces better API" principle. GetLatest should probably be renamed or otherwise refactored.

Philip said...

“Overuse of var can make source code less readable for others. It is recommended to use var only when it is necessary, that is, when the variable will be used to store an anonymous type or a collection of anonymous types.”

I agree with Alexander. Var should only be used for anonymous types. It was designed for anonymous types and for use with LINQ. Using var to implicitly type local variables is not good practice and makes code more unreadable.

Anonymous said...

"var latestUpdate = GetLatest();"

I knew you were going to say that :>

As I said - I have an open mind...

Ilya Ryzhenkov said...

Merlin,

You are just restating what Microsoft told developers in their usual safety manner. What exactly do you think is less readable? Why var should be used only for anonymous types?

Brent said...

I'm keeping an open mind... Here's a post by Rob Conery which contains some additional thoughts:

"The upshot here is that vars generate some serious code - all for good reason when using LINQ. But NOT for a good reason if you’re being lazy - which is the point of this whole post. If you find yourself using “var” anywhere that’s not within a LINQ statement, it’s probably not a good idea."

Ilya Ryzhenkov said...

Brent,

That's all wrong. Using "var" doesn't generate any code. Compiler just infers the type and then acts as if this type was typed in. The code is being generated for anonymous types, not for vars.

Matt Ryan said...

Great list Ilya.

The last was one I'd not quite registered consciously, although now that I think back over the past 6 months of steadily increasing use of var, I think it's definitely been an influencing factor...

Jeff:

Just FYI, and putting aside the renaming possibility for the moment, in my experience I've actually found it really useful to be able to implicitly change the return type of these sorts of creational/factory methods. If at some point later you that an extract interface / split interface/class refactoring is appropriate (perhaps 80% of usage is of a logical subset of the original interface) then implicit typing can reduce the amount of manual change in some scenarios...

To borrow from your example, you may decide to split the LatestUpdate into an interface providing meta-data only, and another one containing the full content of the update...
If most usage just needs the MetaDataForUpdate interface/class, the GetLatest can just return that...
With implicit typing, you avoid having to change the locals calling this method, but the compiler will still catch the 20% of usages that actually need the full ContentOfUpdate (because they are attempting to call a FileBytes property which does not exist on MetaDataForUpdate), and you can just work on that smaller proportion of code.

During refactoring, it almost acts like a strongly-typed version of Duck-typing (http://en.wikipedia.org/wiki/Duck_typing)

This is definitely a minor scenario, and despite the length this comment ended up being :), I don't mean to overstate it... BUT it can be quite convenient.

Most commonly I've found it useful when trying to increase unit test coverage in existing codebases, where there may be numerous existing tests that each create an instance.
Here, running extract interface to facilitate a mock or fake implementation becomes just a little bit easier... For an example, see below.

(Of course, horses for courses, and it won't appeal to those who like both suspenders and a belt... :)

Matt



We can change

class Duck
{
void TalkQuack();
void WalkWaddle();
}

Duck CreateDuckInstance()
{
return new Duck();
}

// line of code that exists in N unit tests...
var speaker = CreateDuckInstance()


To (bold indicating changes)


interface IDuck
{
void TalkQuack();
}


class Duck
{
void TalkQuack();
void WalkWaddle();
}

namespace Tests {
class MockBushLameDuck
{
void TalkQuack();
void CantWalkIsLame();
}
}


Duck CreateDuckInstance()
{
if (Testing)
return new Tests.MockBushLameDuck();
else
return new Duck();
}

// line of code that exists in N unit tests, and can remain unchanged...
var speaker = CreateDuckInstance()

Matt Ryan said...

Oops, lost the important bit of the example while playing with formatting:

Duck CreateDuckInstance()

To

IDuck CreateDuckInstance()

Anonymous said...

I was wondering if this issue was revisited by you Ilya. Are you thinking about leaving this suggestion the way it is now?

jlo said...

After reworking some code and using var wherever possible, I can't say it has provided any benefit and at best obfuscates meaning in most situation.

I can see it as a reasonable substitution in construction:

var jeff = new Jeff();

and with LINQ. After that I don't see the benefit.

I hope the the hint capability will be expanded somewhat to take the various preferences into account.

Anonymous said...

I really am having a hard time to read code with too many vars - it's just a reduction of information. While you may say that it "forces" devs to go with better variable names, I'd still opt for explicity typing *and* good variables (and people who don't care will still use bad naming schemes)...

Anonymous said...

I'd also disagree.

Sounds to me like "It makes your code less readable, so forces you to make it more readable".

Simon Cropp said...

to add more fuel to the fire...

These are my tentatively self imposed rules

-Do use var for anonymous type
-Do use var for constructors
eg var list = new List();
-Do use var for casts
eg var Ilist = (IList)list;
-Consider using var where the variable name implies the type of the variavle
eg var xmlSerializer = GetXmlSerializer();

The idea is to use var where it does not obfuscate the code

With these in mind it would be great if in the resharper config we could define different cases when the var hint is shown.

Unknown said...

Right on, Ilya! Good stuff!

The only thing better than the var keyword would be no keyword at all.

Ruby has forever changed my opinion on necessary keywords and code noise.

Anonymous said...

Completely agree with using var instead of actually typing out the variable type name. It's much quicker, concise and increase the percentage of code typed which actually reflects the algorithm.

One nitpicky detail. "var" is not required to declare an anonymous type variable. You can use type inference to get around this.

static void Example1<T>(T value)
{
T local = value;
}

static void Other()
{
Example(new { Name = "foo"});
}

Anonymous said...

I started a while back with the idea I didn't like var as it would make my code look meaningless and I would need to read methods to figure out what they returned.

I rapidly realised that var was helping me to name methods and properties in a better way, and that removing half a screen width of pointless declaration was a massive boon to code clarity.

Use them, love them, worry if you cannot figure out what an object does by it's name, don't blame var for you having poorly named fiunctions :)

Anonymous said...

"The only thing better than the var keyword would be no keyword at all."

Oh dear me no. From bitter experience, I'm not a fan of declaring new variables whenever I mis-spell/capitalise an existing variable name.

Unknown said...

Ruby has forever changed my opinion on necessary keywords and code noise.

That's an interesting way to put it. I remember back in 1983 when I went from BASIC to Pascal, and it took me a bit to understand this concept of declaring variables before using them.

Ultimately, I've come to conclude that the declaration is useful because it forces you to actually think about what you are doing ahead of time.

Apparently you disagree? Should we just go back to BASIC and Fortran? Can we get more done by not having to declare variables?

Anonymous said...

Before var existed, was anyone in the community thinking "my code would be so much more readable if only I didn't have to type all my local variables"? No, of course not. It was pretty much invented only to support Linq. The fact that it can be used for non-anonymous types doesn't mean it should.

Indeed, I feel your points are mainly spurious. For example, points 2, 3 & 4 are essentially saying "because some coders follow porr practices, everyone should remove useful information from the code". While point 5 refers to the useful information as "noise". The compiler can infer the type, yes. Poor maintainers, however, shouldn't have to work to do this, they should see it explicitly stated.

Brian said...

Who are all of these people that are scrolling back up to the variable declaration or using "Go to declaration" to determine the type of a variable rather than simply hovering over the variable?

Are you guys using something other than Visual Studio for C# development? Monodevelop, perhaps? Doesn't it provide similar features?

It seems to me the flexibility and the Don't Repeat Yourself (DRY) principal demand var usuage wherever possible, and I don't see how this adversely affects practical readability if your variables and APIs have descriptive names.

If you are relying on the variable type to make your program more readable, then you aren't using descriptive enough names. Besides, that also implies that knowing the variable's type affects how you use it, rather than simply using IntelliSense to go member-shopping, as I'd bet most of you do anyway.

It just seems goofy to pretend that you are programming with vim, emacs or notepad, when the IDE takes care of any practical concerns introduced by var declarations.

Unknown said...

Brian,

What is the exact connection between var and DRY principles? I don't get this part.

Besides, code readability > everything else.

Brian said...

Ray, please read my comment again. Readability isn't hurt.

XslSettings xset= new XslSettings();

var xset= new XslSettings();

The first statement is repetitive. DRY.

Владимир said...

I think that using "var" (type inference) is also consistent with modern functional programming ideas realized by such languages as Scala and F#.
In Programming in Scala Martin Odersky emphasize on how
val greetStrings = new Array[String](3)
is generally better than
val greetStrings: Array[String] = new Array[String](3)
because it does not repeat unnecessary Array[String] (both styles are valid in Scala).

Владимир said...

P.S. I basically agree with what Brian said. Most of the time DRY applies, but as Martin Odersky likes to say, "had you been in a more explicit mood, you could have specified the type ... explicitly" :)

BTW, C#, F#, and Scala are better here, than Ruby, because they still use static types.

Anonymous said...

From the points made in the main article it seems this type of refactoring is unique amongst all the great recommendations that resharper makes. This rule makes your code worse until you can manually refactor or rename existing code to add in some meaning that has been removed.

Reshaper is a great tool because it simply lets me refactor code to be better with a few mouse clicks. I don't think resharper would be as great if it had a bunch of rules that only took you halfway to the goal.

I think the decision to keep this feature is a philosophical decision for the Resharper dev team. Are these halfway rules what you want to include into your otherwise concise and complete rule set.

Personally i don't like this rule. If a member of my team used a "var" where it wasn't necessary i would ask them to change it. I would actually like a reverse rule for this. "Don't use unnecessary implicitly typed locals"

Brian said...

Seriously, why are you navigating back to the variable definition to determine the type of variable?

No one seems willing or able to answer this critical question, which is the entire basis of the "type name adds meaning" argument.

Anonymous said...

I've turned off this recommendation and am telling my developers to do the same. Variable type declaration is not equal to variable instantiation. Therefore, you should only use var when you must. I've fought far to many battles in classic ASP and vbscript where the type I thought was going into the variable wasn't the type I ended up with.

Brian said...

"Variable type declaration is not equal to variable instantiation."

If this were true, the compiler would be unable to infer the type.

"I've fought far to many battles in classic ASP and vbscript where the type I thought was going into the variable wasn't the type I ended up with."

Comparing a dynamic language with a strongly-typed one isn't a great way to develop best practices.

Yet again, I have to ask why people are scrolling to the point of variable declaration to determine the type, rather than just hovering over the variable.

Anonymous said...

"Yet again, I have to ask why people are scrolling to the point of variable declaration to determine the type, rather than just hovering over the variable."

That's supported in Visual Studio only. What if you're reading code on paper, on a web page, pdf or plain text editor?

Brian said...

"What if you're reading code on paper, on a web page, pdf or plain text editor?"

If that's a primary design concern, I worry about your development process.

Anonymous said...

"If that's a primary design concern, I worry about your development process."

I guess you've never heard of code reviews.

Brian said...

"I guess you've never heard of code reviews."

Sure, we do them too, just not on stone tablets.

Anonymous said...

Ok, let say that you have something like this.

var message = Inbox.GetMessage();

How do you know if the message is an IMesssage, Message of even just a string?

You say that I should rename my method....do I have to call it Inbox.GetIMessage() or even worst...Inbox.GetStringMessage()???

And by the way, maybe I dno't even have access to this code..maybe iI' using a dll from another provider. You should NEVER change your coding convention because of that.

Naming all your method depending on the return type is totally stupid. That's exactly why Microsoft says to not overuse the var keyword. I agree that var should (could) be used when declaring long named type objects like in this example.

//this is long for nothing
MessageProvider messageProvider = new MessageProvider();

//this is ok
var messageProvider = new MessageProvider();

It should also be used with LINQ. But THATS IT! Don't use it with method. Don't use it inside loops. Stop using var just because you can. If you don't like strongly typed language, go with Ruby or Python and stop blogging about C#.

Brian said...

"How do you know if the message is an IMesssage, Message of even just a string?"

You hover over the variable name. But you probably don't even need to do that, unless you have memorized the entire API/library, which would be a waste of time. In reality, you type the variable name, then a dot, then you shop for the property or method you need, just like everything else.

aDp said...

I vote for Microsoft recomendation.

"var" makes code worse readable.

Anonymous said...

We do a lot of code review, it is required. I also work on a lot of code that is not my own.

To me, I find the use of "var" makes code much more readable and reviewable. I can focus on the behavior of the code better.

I use it just about everywhere.

I personally think the argument of it obfuscating the code doesn't really hold.

Anonymous said...

I hardly ever agree with MS on anything related to development, ... but I have to agree with them on the overuse of var. Why must I hover over variables? I use a laptop most times without a mouse. It's easier for me to read IInterface interface = api.apiMethod() than var interface = api.apiMethod() and judging by the debate all over the net, I'm far from being the only one who prefers it that way.

Brian said...

Appeals to popularity aside, I assume anyone with a problem with var explicitly casts all of their expressions and method params to the appropriate data type, too, so they can clearly see the type. It'd be critical since they've all memorized the entire (current) API, rather than typing a simple dot when they need to access a type member and shopping for it with IntelliSense.

Anyone that dislikes var is going to be completely unable to approach F#.

Chris Marisic said...

var should be used for all complex types, and subjectively used for primitive types.

The quote that Alexander posted “Overuse of var can make source code less readable for others. It is recommended to use var only when it is necessary, that is, when the variable will be used to store an anonymous type or a collection of anonymous types.” appears to have been redacted and replaced by a statement that is vastly different. "However, 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." Can be found on http://msdn.microsoft.com/en-us/library/bb384061.aspx Even this argument is mostly dubious but does make sense for a documentation site like the MSDN.

If the var makes your code less readable it is YOUR FAULT for BAD NAMING of variables.

Владимир said...

"C# documentation generally uses var only when it is required"
This is a bit obsolete approach intended for people who are completely new and unaware of ideas of functional programming, type inference, etc. After reading some books on F#, Scala, etc. (one of my favorites is http://www.functional-programming.net/) it becomes clear when to use and when not to use var. With constructors and type casting operators it doesn't make sense to use explicit types - just makes code less readable. Var also makes sense to use in all cases when type is clear from a context, when type is automatically generated and/or very complicated.

Stryder said...

"Anyone that dislikes var is going to be completely unable to approach F#. "

Good thing that this is a discussion about var in C# then.

Brian said...

@Stryder:

"Good thing that this is a discussion about var in C# then."

C# does not exist in a vacuum.

What about the rest of my comment?

A Booth said...

To me, anonymous variables is a retrograde step to object type Variant, when it became so confusing as to what the object contained, Hungarian notation was the preferred method of identifying type, so instead of

Int32 count;

You would instead have

var iCount;

It also leads to numerous coding errors where there are now assumptions about what type is being assigned, where you were expecting one type and got another. Explicit casting prevents invalid runtime assignments, immediately in the IDE. Instead, you would have to debug trace through, to realize the point of failure, was assigning your Variant the wrong object 20 steps before an exception was thrown.

No. there's a good reason for explicit types and nothing more than lazy coding for anonymous types (Variants)

Anonymous said...

Stop poisoning the world with this nonsense, on top of making code less readable, using var everywhere is just plain LAZY - don't like to type - then find another job because I am sick of walking into gig's where people seem to think this crap is the way to go.

Just because you can drive a car with your feet doesn't mean you should.

Unknown said...

we are talking about "easy to read". Why do we discuss it only for declaration line?

var cat = shop.GetAnimal();

do I care in this line about type? NO. Because I have absolutely beauty variable name. But it's not good example!

Good example to show that we don't care about type at all and focus on our habit to see type on left side... it's way how we using this variable:

var cat = shop.GetAnimal();
...
cat.Meow();

Do I really believe that during reading cat.Meow() I care about type? Why do I need type during the reading?

"Readiness" is defined not by initialization of the variable, it's defined by using variable.

If you eager about using concrete type you MUST write like this:

Cat cat = shop.GetAnimal(); (1)
...
(Cat)cat.Meow(); (2) <--- BE HONEST! :)

Here (2) is a type as you like :D Please be honest, it's not logical to use type in (1) and avoid in (2).

My conclusion, we want to see code without var due to our habits, rather than to make code readable.

Brian said...

"Lazy"?

"Poisoning the world"?

Should we also get off of your lawn?

Anyone that thinks this is about saving typing doesn't really understand the discussion.

Mathieson said...

There's good arguments on both sides - however using var does have the benefit, not listed, of making refactorings change less files.

If I do
var myStuff = StuffFactory.Get();

and then later change the return type of StuffFactory from Stuff to IStuff, the calling code never changes.

Jose Leal said...

Seems that coding OO is not what it used to be...
Maybe an interface to the developer brain to avoid all typing? And linked to the user, no more coding and compiling... Telepathy... :)
Now that was unnecessary, I apologisze, so should MS for trying to attract all the web masters that know some javascript, are unable to think in abstractions and to whom writing(literally)/reading code (my precious) is too hard.
The problem with giving kids candy is that unless you hide the jar and feed them candy yourself, they don't know when to stop...
And yes, I do use var! sensibly, I hope... when I don't know the name of the type and then hoover over the var to get the proper type :D... great tool! (also on using()...)
But hey! Don't let me stop you from coding as you feel like it. If there was only one way of coding and it was the right one, we would not have this conversation at all. And testers do need work:)

Aleksandar said...

I very much disagree with this. If this is so then C# should decide about it NOT some tool added on top. C# is saying why var is there and the circumstances when it should be used. Being smart over the language specification is never a good idea.
var list = new List() might have some sense especially when declaration type is very long, but dragging it into using var just about everywhere is something I totally disagree. In order to read the type you have to dig into the code. That does not have any sense. If C# wanted that, they would tell you to do that.
The problem is that doing it indiscriminately can lead to a serious issues. Take this code

var spaceWidth = count == 0 ? (decimal?)a : null;

Intention is to have spaceWidth to be decimal? yet this is declared within the code Yes this is exactly what a developer would do if he would see decimal? spaceWidth = since var by Refactor has to be used everywhere.