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:
var c = SomeMethod();
Well, to that I'd say you should give your variables more sensible names.
Improved:
var customer = SomeMethod();
Better:
var customer = GetCustomer();
Lets try explicit typing:
Customer customer = GetCustomer();
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 on customer
, just by the name of the variable. If you're not familiar with the code yet, you don't know what methods Customer
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 like Customer
, or Order
, but some processed value, like some sort of Dictionary? Something like:
var ordersPerCustomer = GetOrdersPerCustomer();
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 of Order
. 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:
IEnumerable<IGrouping<Customer,Order>> ordersPerCustomer = GetOrdersPerCustomer();
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
and string
. 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 the m
to a literal number that you want to be typed as decimal
, 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 used var
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 to Dictionary<Customer,Order>[]
, I can simply change my implementation and all code that called it with var
will continue to work (well, the variable declarations at least).