Saturday, August 23, 2008 2:04 AM bart

Appropriate use of Local Variable Type Inference

By now, most – if not all – readers of my blog will be familiar with this C# 3.0 and VB 9.0 feature called Local Variable Type Inference or Implicitly Typed Local Variables. The idea is simple: since the compiler knows (and hence can infer) type information for expressions, also referred to as rvals, there’s no need for the developer to say the type. In most cases it’s a convenience, for example:

Dictionary<Customer, List<PhoneNumber>> phonebook = new Dictionary<Customer, List<PhoneNumber>>();

That’s literally saying the same thing twice: declare a variable of type mumble-mumble and assign it a new instance of type mumble-mumble. Wouldn’t it be nice just to say:

var phonebook = new Dictionary<Customer, List<PhoneNumber>>();

while it still means exactly the same as the original fragment? That’s what this language feature allows us to do without loosing any of the strong typing. The reason it’s very convenient in the sample above is because of the introduction of arbitrary type construction capabilities due to generics in CLR 2.0. Before this invention, types couldn’t compose arbitrarily big and type names tend to be not too long-winded (namespaces help here too).

As convenient as the case above can be, sometimes type inference is a requirement which is introduced by the invention of anonymous types. Typically those are used in projection clauses of LINQ queries although they can be used in separation as well. E.g.:

var res = from p in Process.GetProcesses() select new { Name = p.ProcessName, Memory = p.WorkingSet64 };

This piece of code gives birth to an anonymous type with two properties Name and Memory (notice the type of those properties is inferred in a similar way from their assigned right-hand side) which is – as the name implies – a type with an unspeakable name. In reality the above produces something like:

IEnumerable<AnonymousType1> res = from p in Process.GetProcesses() select new { Name = p.ProcessName, Memory = p.WorkingSet64 };

where the AnonymousType1 portion is unknown to the developer, so type inference comes to the rescue.

Alright. But when is it appropriate to use the type inference feature? Here are some personal rules I tend to apply quite strictly:

  • Do use type inference…
    • where anonymous types are used – you can’t go without it (unless you want to treat them as System.Object of course and only care about their ToString method or so):

      var point = new { X = 10, Y = 5 }; //OK – what else could you do?
      var res = from p in Process.GetProcesses() select new { Name = p.ProcessName, Memory = p.WorkingSet64 }; //OK – what else could you do?
    • when the right-hand side explicitly states the type or the type is clearly inferable by humans given the context:

      var phonebook = new Dictionary<Customer, List<PhoneNumber>>(); //OK – object construction, with generics
      var point = new Point { X = 10, Y = 5 }; //OK – object construction
      var
      customer = (Customer)someObject; //OK – cast
      var products = objects.Cast <Product>(); //Debatable – clearly something with Product objects, but a List<T>, a T[], an IEnumerable<T>, or …? Also, the type is mentioned quite far to the right, which doesn’t work too well with left-to-right parsing humans
  • Don’t use type inference…
    • for assigning constants to variables of built-in types, e.g. what’s the type of the variables below:

      var i = 0123456789; //NOK – an Int32
      var l = 9876543210; //NOK – an Int64
      var name = “Bart”; //Debatable – what do you gain?
    • for “smart” type inference in foreach loops (unless you’re faced with a source of anonymous types):

      foreach (var x in xs) //Debatable – depending on meaningful variable names there might be “good” exceptions to the rule
          ;

      Moreover, foreach inserts casts for you if the source sequence is just an IEnumerable (i.e. not “Of T” aka “<T>”), so the best guess with type inference would be System.Object.
    • when the right-hand side doesn’t clearly indicate the type:

      var something = someObject.WeirdMethod().AnotherProperty; //NOK – need to know the specific API
    • if you want to forcefully exercise some abstraction, e.g. because of your development methodology allowing for “planned refactorings” down the road:

      IAnimal animal1 = new Lion(); //OK
      var animal2 = new Giraffe(); //NOK – will be the most specific type, i.e. Giraffe

      This is an interesting one as all of the refactoring support in the IDE will be based on the most specific type and with var, you force it into the most specific type.

Also, it’s important to realize that mechanical changes to variable declarations (for fun?) can yield undesired behavior due to a change in semantics. A few cases pop to mind:

  • Lambdas don’t play well with type inference. A lambda can either be represented as code or as data (through an expression tree), so without saying what you want, the compiler can’t know. Indeed, not every rhs has a type by itself:

    Func<int> f = () => 123;
    Expression<Func<int>> e = () => 123;
  • Implicit conversion – the long that became an int:

    checked
    {
        long i = 1; // don’t change to var…
        while (true)
            Console.WriteLine(i *= 2); // quiz: does i <<= 1 have the same effect?
    }
  • Explicit interface implementations:
  • static void Main(string[] args)
    {
        IBar b1 = new Bar();
        b1.Foo();
    
        var b2 = new Bar();
        b2.Foo();
    }
    interface IBar
    {
        void Foo();
    }
    
    class Bar : IBar
    {
        public void Foo()
        {
            Console.WriteLine("Bar.Foo");
        }
    
        void IBar.Foo()
        {
            Console.WriteLine("IBar.Foo");
        }
    }
  • Method hiding:
  • static void Main(string[] args)
    {
        Foo f1 = new ExtendedFoo();
        f1.Bar();
    
        var f2 = new ExtendedFoo();
        f2.Bar();
    }
    class Foo
    {
        public virtual void Bar()
        {
            Console.WriteLine("Foo.Bar");
        }
    }
    
    class ExtendedFoo : Foo
    {
        public new void Bar()
        {
            Console.WriteLine("ExtendedFoo.Bar");
        }
    }

In the end, as usual, there’s no silver bullet. However, one should optimize code for reading it (write-once, read-many philosophy). When trying to understand programs (at least imperative ones <g>) we already have to do quite some mental “step though” to absorb the implementation specifics with loops, conditions, class hierarchies, etc. We shouldn’t extend this process of mental debugging or reverse engineering with type inference overhead in cases where it’s not immediately apparent what the intended type is. Even though the IDE will tell you the type of an implicitly-typed local when hovering over it, it’s not the kind of thing we want to rely on to decipher every single piece of code. Similarly, IntelliSense is working great for implicitly typed local variables, but that only affects the write-once side of the story.

After all, every powerful tool imposes a danger when misused. Type inference is no different in this respect.

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Filed under: ,

Comments

# re: Appropriate use of Local Variable Type Inference

Saturday, August 23, 2008 3:05 AM by Omer van Kloeten

"Don’t use type inference in foreach"

It's a matter of taste, but I would have to disagree - I don't find it a "DO NOT" rule, but rather a "CONSIDER". It all ends up with arguments pro and con readability and that's subjective most of the time. I, for one, do not like to specify a type name that will take up half the screen (for instance, a typed dataset's row type) in a foreach loop when I can avoid it.

Also, LVTI is required in LINQ's let statements, so you have no choice there regarding the rules you mentioned. I usually default to casting the result of the let statement to the desired type to force LVTI to choose it.

# Dew Drop - August 23, 2008 | Alvin Ashcraft's Morning Dew

Saturday, August 23, 2008 7:17 AM by Dew Drop - August 23, 2008 | Alvin Ashcraft's Morning Dew

Pingback from  Dew Drop - August 23, 2008 | Alvin Ashcraft's Morning Dew

# re: Appropriate use of Local Variable Type Inference

Saturday, August 23, 2008 1:39 PM by Jonathan Allen

" when the right-hand side doesn’t clearly indicate the type:"

Why?

If you are using an anonymous type you don't care what class is returned. So why do you care when it isn't an anonymous type?

Seems to me what really matters is how the object is bing used, its type is just book keeping.

To put it another way, consider your example again:

var something = someObject.WeirdMethod().AnotherProperty

Why do you care what type "something" is but not care about the object returned by "WeirdMethod"?

# re: Appropriate use of Local Variable Type Inference

Saturday, August 23, 2008 10:51 PM by bart

Hi Omer,

I agree on the foreach case to be "debatable" from situation to situation. Carefully chosen variable names or method names (e.g. for iterators returning a sequence consumed by foreach) can definitely help, e.g. customers or GetCustomers(). For strongly typed datasets, the "table" referenced in the "in clause" typically reveals the type too.

You're absolutely right about the let clause (not a "let statement" to be nitpicky) to be another case where type inference is a requirement.

Coming from the framework development side of things, I'm more in the extremist camp opting for more verbosity to help with maintainability of large code bases, reading changelists from a few years back written by other people (or even from yourself after such a time). As Jeffrey Snover (PowerShell) says: "sometimes verbosity is your friend but sometimes it can be your enemy too".

In the end it's as you say a matter of taste.

Thanks,

-Bart

# re: Appropriate use of Local Variable Type Inference

Saturday, August 23, 2008 11:16 PM by bart

Hi Jonathan,

I'm one of those folks coming from a left-to-right culture who likes to see the type; seeing "var" means to me that I'll be able to infer the type straight away when moving on. For anonymous types, the shape of the type will be indicated on the right-hand side (which is - to some extent - even more interesting for the reader as all of the properties are immediately indicated for further consumption in the local method scope, but that would need to be subject of a separate post on appropriate use of anonymous types). This being said, it's possible of course to make the anonymous type by itself cumbersome when assigning complex expressions to its properties (something that on the other hand might indicate "reckless" composition that will be hard to debug).

Assume you're reading a chunk of code that calls out to some random API, calling a method WeirdMethod:

var something = someObject.WeirdMethod().AnotherProperty;

To come back to your question why I don't seem to care about the type of WeirdMethod() - I do. In general, I don't like this kind of chaining for non-fluent APIs. Required null-checks might be omitted (and no, Spec#'s verification guarantees wouldn't be a good excuse start writing this kind of code either IMO :-)),  exception stack traces with line numbers might be confusing (where in the chain did it blow up) and more such horror stories concerning step-by-step debugging one method call at a time checking the return value after every step. In fact, the line above (assuming we know the type of someObject) already has var² complexity.

The main problem I have with this is that the reader has little context to learn more about some API use to help in understanding or debugging (in the former case, reading code listings on a patio on a hot summer evening is typically a setting without tools; the latter case is typically a setting with tools). For some reason you want to learn more about AnotherProperty - if you'd have the type of the WeirdMethod() result available, you know where to look straight away. If not, you have to work your way back to a "known type" point and go from there. Also, just seeing the type name might set quite some context (e.g. OrderServiceProxy) that's very useful to absorb specific aspects of the code (wbe service calls, interop code, specific APIs with certain reputations, etc).

Obviously, all of this depends from case to case and as usual the exception confirms the rule.

Thanks,

-Bart

# re: Appropriate use of Local Variable Type Inference

Sunday, August 24, 2008 10:56 AM by Omer van Kloeten

I was actually going to write 'let expression' and have no idea why I wrote 'statement'. Still, clause is probably best :)

# re: Appropriate use of Local Variable Type Inference

Sunday, August 24, 2008 2:24 PM by bart

Hi Omer,

Indeed, expression would be better, but clause is preferrable for the following reason. Expressions can be composed of other expressions and/or clauses where clauses can't stand by themselves while expressions can (for example: query expression > where clause > predicate expression).

-Bart

# WMOC#17 - PhotoSynth, Reflector move forward - Service Endpoint

Pingback from  WMOC#17 - PhotoSynth, Reflector move forward - Service Endpoint

# Friday Links #14 | Blue Onion Software *

Friday, August 29, 2008 11:07 AM by Friday Links #14 | Blue Onion Software *

Pingback from  Friday Links #14 | Blue Onion Software *

# reverse phonebook

Saturday, September 13, 2008 8:48 PM by reverse phonebook

Pingback from  reverse phonebook

# Appropriate Use of Type Inference or (2 var | ! 2 var) &laquo; Roman&#8217;s Blog

Pingback from  Appropriate Use of Type Inference or (2 var | ! 2 var) &laquo; Roman&#8217;s Blog

# “The C# Programming Language Third Edition” and thoughts on language evolution

Sunday, October 19, 2008 7:23 PM by B# .NET Blog

With a hypothetical next release of the C# language around the corner (more about that after Anders,

# Recent URLs tagged Assign - Urlrecorder

Thursday, February 12, 2009 8:31 AM by Recent URLs tagged Assign - Urlrecorder

Pingback from  Recent URLs tagged Assign - Urlrecorder