In a book I'm reading it states the implicit typing makes the following code clearer than if you didn't use the var
keyword:
var words = new[] { "a", "b", null, "d" };
foreach (var item in words)
{
Console.WriteLine(item);
}
It seems to me that the opposite is true: if you used string
instead, then readers of the code would immediately know it was a string in the foreach loop, instead of having to look up in the code where the variable is defined.
How does implicit typing make the above code clearer?
Addendum
The book is C # 3.0 - Die Neuerungen. schnell + kompakt which is in German, the actual text is:
Das Schluesselwort var kann auch beim Durchlaufen von foreach-Schleifen verwendet werden, um somit den Code uebersichtlicher und einfacher zu gestalten. Besonders bei komplexen Typen kann man auf diese Art und Weise Programmierfehler verhindern.
here's my translation:
The var keyword can also be used when iterating through foreach loops, thus making the code easier and simpler to create. Especially when using complex types, this can prevent programming errors.
Ok, reading it more closely now he actually states that var
in a foreach loop makes the code easier to create but not necessarily easier to read.
I don't think I really understood the good aspects of implicit typing in C# until I started using F#. F# has a type inference mechanism that is in some ways similar to implicit typing in C#. In F#, the use of type inference is a very important aspect of code design that can really make the code more readable even in simple examples. Learning to use type inference in F# helped me understand those situations when implicit typing could make C# more readable, as opposed to more confusing. (The Linq case is, I think, fairly obvious, but many cases are not.)
I realize this sounds more like a plug for F# than an answer to the question re.C#, but it's not something that I can pin down to a simple set of rules. It's a learning to look at the code through new eyes when thinking about things like readability and maintenance. (That, and maybe it is a little bit of a plug for F#, lol.)
When you need to change your code, you'd have to do it in less places. No more Dictionary or longer type declarations, no more
Some.Very.Long.Class.With.Very.Long.Path<string> declaration = functionParameter[index]
, etc.Although I do agree that when it is used in other situations than small methods, it might get very confusing.
Well, you have picked up important idea - that overuse of var can be detrimental indeed and that in cases where actual type is pretty simple it should be stated as such.
var shines however when dealing with larger inheritance hierarchies and templates. You can also read it as "I don't care - just give me data" While templates in C# don't have expressive power of their C++ counterpart they do have more expressive power than Java's generics and that means that people can make constructs which are not just awkward but also hard to located if you have to nail exact type explicitly.
For example - imagine a template wrapper around several kinds of DataReader-s for talking to SQL - so that you can still be efficient (call sproc, get results, done) but without the burden of housekeeping (closing the reader and connection, retrying or errors etc). The code that uses it will just call one function, made to have as short syntax as possible and it will return a wrapper which will act like smart pointer in C++ - act like DataReader for your code but also handle all sideways things. So it looks as simple as:
In a case like this, not just that you couldn't care less how is wrapper named and declared, you don't even care to know it's name - for your code it's irrelevant. You just want your darn data and to go on :-) without dealing with anyones long declarations.
It literally allows you to choose when you care about the full type declaration and when not. It's not all or nothing thing and you'll find yourself using both styles.
Another place where you'll be happy to have it is lambda expressions if you start using them. If you use lambdas in C# it will almost always be because you want some short, compact code that will run once and it's either not worth the trouble to turn into a regular method or it depends on local variables from the host method.
Oh and even VS editor will infer full type for you, offer auto-completion and complain if you try to use something it can't do, so var doesn't break type safety at all (new C++ got it's var equivalent as well - long overdue).
Using implicit typing is a guideline, not a law.
What you brought up is an extreme example where implicit is certainly not ideal.
Clean here means less redundant. Since it is trivial for the compiler to infer that the type of the object is
string[]
, it is considered verbose to specify it explicitly. As you point out, however, it may not be so obvious to the human reading the code.I think it's odd that only C# and Java programmers seem to suffer from an affliction that prevents them from extracting information from the context of code, while developers of Python, JavaScript, Ruby, F#, Haskell and others seem to be immune to this. Why is it that they appear to be doing fine, but us C# programmers need to have this discussion?
If foregoing explicit type declarations is sloppy or lazy, does that mean there's no high quality, readable Python code? In fact, don't many people praise Python for being readable? And there are many things that irk me about dynamic typing in JavaScript, but lack of explicit type declarations isn't one of them.
Type inference in statically typed languages should be the norm, not the exception; it reduces visual clutter and reduncancy, while making your intention clearer when you do specify a type explicitly because you want a less derived type (
IList<int> list = new List<int>();
).Some might argue a case against
var
like this:Well, to that I'd say you should give your variables more sensible names.
Improved:
Better:
Lets try explicit typing:
What information do you now have that you did not have before? You now know for certain it's of type
Customer
, but you already knew that, right? If you're familiar already with the code, you know what methods and properties you can expect oncustomer
, just by the name of the variable. If you're not familiar with the code yet, you don't know what methodsCustomer
has any way. The explicit type here added nothing of value.Perhaps some opponents of
var
might concede that in the above example,var
does no harm. But what if a method doesn't return a simple and well-known type likeCustomer
, orOrder
, but some processed value, like some sort of Dictionary? Something like:I don't know what that returns, could be a dictionary, a list, an array, anything really. But does it matter? From the code, I can infer that I'll have an iterable collection of customers, where each
Customer
in turn contains an iterable collection ofOrder
. I really don't care about the type here. I know what I need to know, if it turns out I'm wrong, it's the fault of the method for misleading me with its name, something which cannot be fixed by an explicit type declaration.Lets look at the explicit version:
I don't know about you, but I find it much harder to extract the information I need from this. Not in the least because the bit that contains the actual information (the variable name) is further to the right, where it will take my eyes longer to find it, visually obscured by all those crazy
<
and>
. The actual type is worthless, it's gobbledygook, especially because to make sense of it, you need to know what those generic types do.If at any point you're not sure what a method does, or what variable contains, just from the name, you should give it a better name. That's way more valuable than seeing what type it is.
Explicit typing should not be needed, if it is, there's something wrong with your code, not with type inference. It can't be needed, as other languages apparently don't need it either.
That said, I do tend to use explicit typing for 'primitives', like
int
andstring
. But honestly, that's more a thing of habit, not a conscious decision. With numbers though, the type inference can screw you if you forget to add them
to a literal number that you want to be typed asdecimal
, which is easy enough to do, but the compiler won't allow you to accidentally lose precision so it's not an actual problem. In fact, had I usedvar
everywhere it would've made a change of quantities in an large application I work on from integers to decimal numbers a lot easier.Which is another advantage of
var
: it allows rapid experimentation, without forcing you to update the types everywhere to reflect your change. If I want to change the above example toDictionary<Customer,Order>[]
, I can simply change my implementation and all code that called it withvar
will continue to work (well, the variable declarations at least).