My boss forbids me to use var
as it would cause boxing and slowing down the app.
Is that true?
My boss forbids me to use var
as it would cause boxing and slowing down the app.
Is that true?
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 :)
x
(in Visual Studio) and show the boss that it says "int"? –
Arcadia 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
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.
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 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.
var
as "surprise me!" –
Poaceous 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 Dictionary<String,List<KeyValuePair<MyNamespace.MyType1,MyNamespace.MyType1>>>
and don't have it aliased with a using
–
Marcenemarcescent 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 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...
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.
© 2022 - 2024 — McMap. All rights reserved.
var x = 0
vsint 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