Does var keyword in C# cause boxing?
Asked Answered
R

6

38

My boss forbids me to use var as it would cause boxing and slowing down the app.

Is that true?

Reserve answered 24/8, 2010 at 10:48 Comment(11)
var x = 0 vs int x = 0 is one of the cases where type inference isn't worth it anyway. But "sign f**k these clueless perf junkies" anyway.Minutely
Not programming related. Discuss sports somewhere else!Exegete
wow. it's people like you who have a valid reason to pee in your bosses coffee :)Gangrel
This question would be more interesting if it asked "can you think of any var initializer that causes boxing without using a cast?"Falsetto
Here's a link to the overview of the 'var' specification in the C# 3.0 spec, about half way down msdn.microsoft.com/en-us/library/ms364047%28VS.80%29.aspxCounterintelligence
vars dont cause boxing, but I still dont like var because it makes code look little ugly having too many var, I want code to look good and be complete, vars give me feel of poorly coded as its just laziness to write proper types, var should only be used in linq etc where it may be very lenghthy to write types.Obscurantism
@Akash Kava: No flamewars in the comments, pleaseCaricature
I write all my software in binary machine code. Anything else would be lazy.Hypoderm
@nikie, sorry if you felt like flamewar, I am just expressing my opinion about why vars should not be used.Obscurantism
@Akash Kava: Expressing your opinion about why vars shouldn't be used is a flamewar starter. It's subjective and argumentative. Just like expressing your opinion that Java is better than .NET or why dynamic typing shouldn't be used would be. Put it in your blog if you want to discuss it.Caricature
@Akash Kava: your opinion was just that: an opinion, which is inherently subjective. I think var makes code cleaner. These opinions have nothing to do with "does var cause boxing".Thigh
G
52

An approach that might work is to write these two methods:

public static void WithInt()
{
    int x = 5;
    Console.WriteLine(x);
}

public static void WithVar()
{
    var x = 5;
    Console.WriteLine(x);
}

Compile, and use ildasm to examine the produced CIL. Show your boss.

edit @ck has done all but the last step for you :)

Groundling answered 24/8, 2010 at 10:54 Comment(5)
Ha, or how about just hover the mouse over x (in Visual Studio) and show the boss that it says "int"?Arcadia
I suggest some sensitivity when presenting this "in your face!" evidence to your boss - he may genuinely have confused this issue with something else and demonstrating his wrongness won't win favours with him IMO.Forum
I propose more "in your face!"-ness towards bosses in general - the more they get used to it the more acceptable it becomes for the rest of us. And it's funnier.Tramp
Yea, let me know how your termination goes after you tell your boss he/she is wrong.Viscountess
Well I said my boss today var is not boxing he is wrong! He said:"really ah ok". Then he saw my code: foreach(var item in ItemsList){} telling me now to replace the var with the proper type like string. :PReserve
M
37

Following on from Aakash's answer, here is the IL: (thanks LINQPad)

WithInt:
IL_0000:  ldc.i4.5    
IL_0001:  stloc.0     
IL_0002:  ldloc.0     
IL_0003:  call        System.Console.WriteLine
IL_0008:  ret         

WithVar:
IL_0000:  ldc.i4.5    
IL_0001:  stloc.0     
IL_0002:  ldloc.0     
IL_0003:  call        System.Console.WriteLine
IL_0008:  ret      
Marcenemarcescent answered 24/8, 2010 at 12:37 Comment(1)
Wait...what is that difference I see? Oh nevermind, that was just a spot on my monitor :)Berky
H
32

Why are so many people cursed with bosses who are dumb? Revolution, brothers!

Your boss needs to read the documentation. var causes the compiler to figure out the variable type by looking at the static type of the initialization expression. It doesn't make the slightest difference at runtime whether you specify the type by hand or you use var and let the compiler figure it out for you.

Update In a comment under the question, Hans Passant asks

can you think of any var initializer that causes boxing without using a cast?

An example of a self-contained expression that forces such a conversion is:

var boxedInt = new Func<int, object>(n => n)(5);

But that is just identical to:

object boxedInt = new Func<int, object>(n => n)(5);

In other words, this doesn't really have anything to do with var. The result of my initializer expression is object, hence var has to use that as the type of the variable. It couldn't be anything else.

Hypoderm answered 24/8, 2010 at 10:49 Comment(11)
Well, the type inferer could, in theory, interfere a boxed type for a literal. But I guess it doesn't. ++ for rant.Minutely
Even if it did the boss is guilty of micro-optimisation, and even if that wasn't true he's guilty of favouring performance over maintenance which is almost universally wrong. Why are the people in charge always the ones who don't know what they're talking about?Tramp
@delnan: What would be the reason for doing so?Poaceous
@annakata: It's called "the Peter principle": en.wikipedia.org/wiki/Peter_PrincipleHunan
I'm not defending the bullshit by OP's boss in anyway, I'm just nitpicking :)Minutely
@Fredrik: "in time, every post tends to be occupied by an employee who is incompetent to carry out their duties" awesome stuff, thanks for linkTramp
Even simpler than the Peter Principle is the recursive proof: if your boss is stupider than you, why was he hired? Well, his boss is stupider than him. And so on.Hypoderm
DISCLAIMER. I am not referring to my present employers! (If anything I have the opposite problem, I'm cursed with a smart boss).Hypoderm
@Daniel: Stop sucking up to your boss :-) Is he reading Stackoverflow? ;-)Hushhush
Oh, he doesn't need to - that's how smart he is! (Okay, I think I'm out of this hole now...)Hypoderm
@delnan - I think you may be thinking of Java and how they have named boxing classes like Integer, etc. In C# the universal boxing type is object, and any type inference engine worth its salt is going to have to do better than that.Hypoderm
P
32

That's not true at all.

var just means "dear compiler, I know what the type is, and so do you, so let's just move on shall we."

It makes the code shorter and some find this more readable (others find it less readable), but there's no performance penalty whatsoever.

Poaceous answered 24/8, 2010 at 10:52 Comment(12)
"dear compiler..." nice :) But point of order I think it means "Dear compiler I don't care what the type is, you decide"Tramp
@annakata: "you decide" is fine too, as long as "surprise me!" is out of the question :)Poaceous
If the interfered type (provided it is correct, of course) surprises you, you should propably take a closer look - at least in Haskell (only type-interfering language I ever used) it usually means you messed something up.Minutely
@delnan fair enough, there are cases where it may not be evident, but I wouldn't want to define the meaning of var as "surprise me!"Poaceous
I tend not to use var, unless 1. The type is absolutely clear (for instace: var customer = new Customer();’), or 2. the type cannot be written, because it is anonymous, or 3. In cases where ‘I believe’ the type is obvious enough. Example of this last point: I for instance tend to use var for the result of LINQ queries, where the type is an IEnumerable<T> or IQueryable<T>. I use these queries often in small methods that return a T[] and in that case I find var clear enough. In all other situations, I write out the type.Hushhush
@annakata: No, it doesn't mean "I don't care what the type is" - it means "I want the type to be the type of the expression on the right hand side of =". There's no guessing involved. The compiler isn't at liberty to choose a type arbitrarily. The specification lays it down very clearly.Epicure
@Jon: perhaps I spoke too lightly. I'm not suggesting the compiler guesses or that there's any kind of uncertainty here, I'm trying to express that var allows me to not care about the type of the LHS except in terms of what the RHS gives me, whatever that may be. The value is in the decoupling to me.Tramp
@annakata: Right, in that sense it's reasonable. I just don't want anyone to think it's ambiguous :)Epicure
@Hushhush - 3. When I have a stupidly long type, e.g. Dictionary<String,List<KeyValuePair<MyNamespace.MyType1,MyNamespace.MyType1>>> and don't have it aliased with a usingMarcenemarcescent
@ck: I agree. I tend to use var in this situation. While it hides the type and makes the code less understandable, it improves readability a lot. I think this is a good case.Hushhush
@Hushhush - I use var aggressively, and there's certainly a discussion to be had (and indeed plenty around already) about the conceptual value of var - but I assert that expressing a type != clarity and not needing to know is the point - it doesn't matter what the thing is but how I use it. It's almost duck typing.Tramp
@Annakata: Perhaps this is a matter of taste. I know in the functional world (Lisp, F#) they don't care about types. However, I often find it very useful in my C# applications to understand what the type is. Leaving out the type could mislead the user, because he has to figure it out himself. But I think that in many situations, a very well written program should perhaps not really need the types to be explicitly shown. Perhaps the problem is, that I'm not that good of a programmer ;-)Hushhush
F
10

Maybe your boss is an old Visual Basic (as in <= 6.0) programmer used to the VARIANT type. If you didn't specify the type of your variable explicitly in your DIM statement, it was a VARIANT which is a sort of union if I recall correctly. You could view this as a sort of "boxing" and "unboxing" when passing such variables to functions.

Sometimes people get confused. Ask your boss about his Visual Basic war stories. Listen, learn and earn some sympathy at the same time! As you leave the office you could point out that the c# compiler figures this stuff out at compile time and that "boxing" isn't an issue anymore.

Don't expect your boss to have to keep up with the newest changes to languages/APIs. This isn't about being dumb. It's about having other stuff to do. His job, for instance.

Edit: As noted in comments below, though, telling you not to use var for the wrong reasons is probably not his job...

Fachanan answered 24/8, 2010 at 13:2 Comment(4)
+1 for explaining the bosses's behaviour. It sounds quite likely. But if the boss thinks his knowledge stays relevant without him keeping up, then he is at least a bit dumb. And if he spends his time telling programmers which keywords to use (although they know better than he does), then he isn't doing his job, either.Caricature
I don't kow. I think it is reasonable to expect your boss to be educated on the platforms in use at your company especially if he is dictating how you use those platforms.Berky
@Brian - Exactly. If you're going to dictate keywords, you'd better know what you're talking about. If you don't want to keep up on the latest technical developments, that's fine, but don't micromanage to the point of dictating what keywords are acceptable.Laius
I will have to add: var is very usefull ......to code fast using var is good, but I believe there are two main path to use var or not. if the right side of your statement is simple then var is nice as in var = new List<class>(); if the right side is a bit too complicated to guess what var IS then don't.... just state what you are specting so maintance becomes easier.Martel
A
3

Actually, var can also avoid boxing in some very specific instances.

static void Main(string[] args)
{
    List<Int32> testList = new List<Int32>();
    IEnumerator<Int32> enumAsInterface = testList.GetEnumerator();
    var enumAsStruct = testList.GetEnumerator();
}

Results in the following IL:

.method private hidebysig static 
    void Main (
        string[] args
    ) cil managed 
{
    // Method begins at RVA 0x2050
    // Code size 27 (0x1b)
    .maxstack 1
    .entrypoint
    .locals init (
        [0] class [mscorlib]System.Collections.Generic.List`1<int32> testList,
        [1] class [mscorlib]System.Collections.Generic.IEnumerator`1<int32> enumAsInterface,
        [2] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32> enumAsStruct
    )

    IL_0000: nop
    IL_0001: newobj instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor()
    IL_0006: stloc.0
    IL_0007: ldloc.0
    IL_0008: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<int32>::GetEnumerator()
    IL_000d: box valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>
    IL_0012: stloc.1
    IL_0013: ldloc.0
    IL_0014: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<int32>::GetEnumerator()
    IL_0019: stloc.2
    IL_001a: ret
} // end of method Program::Main

Note that the 2nd one (the var assignment) knows that this return value is a valuetype (struct) from inside List and can more efficiently use it - even though the contract from List.GetEnumerator returns an IEnumerator. This will remove the boxing operation on that struct and results in more efficient code.

This is why, for instance, in the following code the foreach loop and the first using/while pair doesn't cause garbage (due to a lack of boxing) but the 2nd using/while loop does (since it boxes the returned struct):

class Program
{
    static void Main(string[] args)
    {
        List<Int32> testList = new List<Int32>();

        foreach (Int32 i in testList)
        {
        }

        using (var enumerator = testList.GetEnumerator())
        {
            while (enumerator.MoveNext())
            {
            }
        }

        using (IEnumerator<Int32> enumerator = testList.GetEnumerator())
        {
            while (enumerator.MoveNext())
            {
            }
        }
    }
}

Note also that changing this from a "List" to an "IList" will break this optimization since the IList can only infer that an interface of type IEnumerator is coming back. With the List variable the compiler can be smarter and can see that the only valid return value is a [mscorlib]System.Collections.Generic.List`1/Enumerator and can therefore optimize the call to handle this.

While I understand that this is a very limited case, it may be an important one especially on devices that don't do full incremental garbage collection and pause your threads to do a mark/sweep.

Aeneid answered 13/8, 2013 at 13:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.