How does implicit typing make code clearer?
Asked Answered
A

13

9

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.

Aswan answered 6/8, 2010 at 10:0 Comment(13)
Personally, whenever I see the var keyword in C#, I smell sloppy code. IMO, the author of that book is just wrong, unless there's more context that somehow puts this into perspective.Tasso
I can't help since I agree with you. I've generally considered using var like this to just be lazy coding though have wondered if there is a reason since I've seen people putting code snippets on here with this sort of thing in... I always thought that var was just for when you don't know the type (anonymous types, etc.)Decomposer
you are right in this case,but var k = new MyClass() is better than MyClass k = new MyClass().Agrimony
@tdammers: so you really prefer Dictionary<string, int> map = new Dictionary<string, int>(); to var map = new Dictionary<string, int>();? I know, I don't.Bushey
btw, what is the book's name?Agrimony
@Brian: Yes, in fact I do. IDictionary<string, int> map = new Dictionary<string, int>(); would be even better, because it expresses that I'm interested in the fact that it's a string/int dictionary, but that the actual choice of implementation is secondary. Strongly-typed programming has saved my butt more than once, and I prefer the compiler yelling at me over my boss.Tasso
Actually, I don't see how the use of explicit typing would make the code above clearer. words are strings. I can easily tell that by looking at the code and all you do is print the words. I don't need extra info to understand that.Bushey
@Tasso good point using interfaces, but still there are many cases where I just don't see the point in repeating what you, me and the compiler already know but YMMV.Bushey
I've yet to see a problem caused by type inference other than readability concerns in select circumstances. @tdammers: "Strongly-typed programming has saved my butt more than once, and I prefer the compiler yelling at me over my boss" -- the compiler will still yell at you if you screw up when using var; it's still strongly-typed.Intone
possible duplicate of What's the point of the var keyword?Greed
also a dupe of: https://mcmap.net/q/15983/-use-of-var-keyword-in-cGreed
I've addressed your addendum in my answer.Huck
Agree with the original comment: usage of var tends to mean sloppy code. It makes it more difficult to read in 9 out of 10 cases. I just took a look through a bunch of my projects, and couldn't find one good reason to use var instead of explicit types.Husted
A
12

Personally, I'd agree with you. I'm not sure if clearer is the word I would use but in certain situations the var keyword can certainly make it cleaner, i.e:

var myClass = new ExtremelyLongClassNameIWouldntWantToTypeTwice();
Aneurysm answered 6/8, 2010 at 10:3 Comment(0)
M
12

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).

Motorist answered 7/8, 2010 at 0:34 Comment(1)
Names are hard and by definition always ambiguous. Your argument that type information is somehow superfluous "gobbledygook" is perplexing. How can you understand the behavior of any piece of code without understanding what code (type) is involved? How can you be sure of the type if you're forced to make assumptions? Var makes code harder to read because it removes vital information. Use of it should be reserved for situations where it's required.Scute
C
9

In this case it doesn't, which is just my subjective opinion of course. I only use it when the type is elsewhere on the same line like:

var words = new List<String>();

I like var, but I wouldn't use it like in your example as it is not clear what the type is.

Chickamauga answered 6/8, 2010 at 10:4 Comment(2)
This is something I hadn't really considered. I might start using it when I'm just declaring and newing at the same time like this.Decomposer
+1, this is the same thing I do, too. That way the type of the variable is still obvious by reading the line, and you don't have to type it twice.Perusal
H
5

It's clearer, in the sense of less noise/redundancy. The type of words can be easily deduced by the new[] { ... } statement, both by the compiler and the developer. So var is used in stead of string[], as the latter can visually clutter the code.

It's clearer, in the sense of transparency. You can swap the actual value with an instance of any other type, as long as it's an enumerable type. If you didn't use var, you'd have to change both of the declaration statements in the example.

It's clearer, as it forces you to use good variable names. By using var, you cannot use the type declaration to indicate the contents of the variable, so you'll have to use a descriptive name. You only declare a variable once, but you may use it many times, so it's better to be able to figure out the contents of the variable by it's name. From this perspective, word would have been a better choice for the loop variable name.

Please note that the above reasoning is done from the author's perspective. It doesn't necessarily reflect my personal opinion :)

Edit regarding your addendum:

As I mentioned before, you can swap the underlying collection type, without having to update all your foreach loops. This does make it easier to create and change your code, but doesn't necessarily prevent programming errors. Let's look at both cases after we introduce a Word class as a replacement of the plain strings:

If we don't use the var keyword, the compiler will catch the error:

var words = new[] { new Word("a"), new Word("b"), null, new Word("d") };

// The compiler will complain about the conversion from Word to string,
// unless you have an implicit converion.
foreach (string word in words)
{
    Console.WriteLine(word);
}

If we do use var, the code will compile without errors, but the output of the program will be completely different, if the Word class hasn't (properly) implemented ToString().

var words = new[] { new Word("a"), new Word("b"), null, new Word("d") };

foreach (var word in words)
{
    Console.WriteLine(word); // Output will be different.
}

So, in certain cases subtle bugs can be introduced when you use var, which would have been caught by the compiler otherwise.

Huck answered 6/8, 2010 at 11:5 Comment(1)
"it forces you to use good variable names". I personally assure you, it does no such thing. But I get your point.Wuhu
T
3

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.

Trumpery answered 6/8, 2010 at 10:5 Comment(0)
N
3

The example is poor, as many examples demonstrating syntactic sugar tend to be - syntactic sugar helps where things are complicated, but nobody likes complicated examples.

There are two cases where you might want to use var, and one where you must:

Where you might want it:

  1. It can be useful in experimental code, when you are switching the types involved quickly while exploring your problem-space.
  2. It can be useful with complicated generic-based types such as IGrouping<int, IEnumerable<IGrouping<Uri, IGrouping<int, string>>>> which can especially happen with intermeditary states within complex queries and enumeration operations.

Personally, I prefer to use even the complicated form over var, as it doesn't cost someone reading it who doesn't care about the exact type (they can just skip it thinking "complicated grouping type"), but is clear to someone who does care without their having to work it out themselves.

Where you need it:

In dealing with anonymous types, in code like:

var res = from item in src select new {item.ID, item.Name};    
foreach(var i in res)    
    doSomething(i.ID, i.Name);

Here res is an IEnumerable or IQueryable of an anonymous type, and i is of that anonymous type. Since the type has no name it's impossible to explicitly declare it.

In this last case, it is not syntactic sugar, but actually vital.

A related gripe, is that SharpDevelop used to have it's own while-editting form of var; one could type:

? words = new string[] { "a", "b", null, "d" };

And at the semi-colon, the editor would produce:

string[] words = new string[] { "a", "b", null, "d" };

Which gave (especially in more complicated cases) the advantage of typing speed along with producing explicit code. They seem to have dropped this now that var does conceptually the same thing, but it's a pity to have lost the typing shortcut to the explicit form.

Nightclub answered 6/8, 2010 at 11:22 Comment(0)
I
2

Using implicit typing is a guideline, not a law.

What you brought up is an extreme example where implicit is certainly not ideal.

Itching answered 6/8, 2010 at 10:4 Comment(1)
I'd say the variable name item in the example isn't ideal; word would be a lot better, as it enables you to guess the type string.Huck
H
2

It makes the code clearer when

  1. You have a class with a really long name.
  2. You have linq queries.
Heinrick answered 6/8, 2010 at 10:12 Comment(1)
I think the questioner is referring specifically to the code given in the question.Trumpery
S
2

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.)

Strathspey answered 6/8, 2010 at 16:42 Comment(1)
There is something to it, now that you mentioned, like getting cured from traumas inflicted by piles of old code :-) and realizing that compiler was able to locate the type long time ago but that just wasn't exposed to reduce our RSI.Surah
T
1

If you wanted to make this code more explicit, I would suggest expanding the new instead of removing var:

var words = new string[] { "a", "b", null, "d" };

Resharper will give you hints to remove redundant code with that example, but you can turn those hints off if you like.

The argument for using var is that in many cases the type identifiers for local variables are redundant, and redundant code should be removed. By removing redundant code, you can make the cases where you do actually care clearer, for example if you want to enforce a specific interface type for a local variable:

ISpecificInterface foo = new YourImplementation()
Trodden answered 6/8, 2010 at 10:17 Comment(0)
K
0

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.

Killingsworth answered 6/8, 2010 at 10:8 Comment(0)
L
0

The primary benefit of explicit typing is in my view that it's possible by just looking at the code what type the variable has. So readability is increased.

And the primary benefits of implicit typing are:

  • Reduces program text in particular for long type names (classes, interfaces) thus improving readibility
  • Causes fewer changes when a return type of a method changes.

It looks as if both options improve readability.

So I guess it depends on your preferences and maybe also on the programming guidelines in your team. With current (refactoring) tool support in IDE's it has become much easier to change type names (a no brainer) so the reason that implicit typing reduces changes has virtually disappeared from an effort perspective.

I'd suggest: Do what works best for you. There is no right or wrong. Try each approach for a while (e.g. by configuring the options of your favorite refactoring tool), then use what makes your life as a developer easier.

Lightproof answered 6/8, 2010 at 11:24 Comment(0)
S
0

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:

using (var r = S.ExecuteReader("[MySproc]", params))
{
    while ((+r).Read())
    (
       // get my data and be done
    )
} // at this point wrapper cleans up everything

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).

Surah answered 9/8, 2010 at 6:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.