Does passing a value type in an "out" parameter cause the variable to be boxed?
Asked Answered
A

4

15

I'm aware that boxing and unboxing are relatively expensive in terms of performance. What I'm wondering is:

Does passing a value type to a method's out parameter cause boxing/unboxing of the variable (and thus a performance hit)? Can the compiler optimize this away?

  int number;
  bool result = Int32.TryParse(value, out number);
Autoerotic answered 26/1, 2011 at 16:29 Comment(2)
Lookup premature optimization. Parsing an integer (parsing in general) is way, way more costly than a simple boxing operation.Beltane
@Dykam: True. I'm just using TryParse as an example, though.Autoerotic
K
20

As others have pointed out, there's no boxing here. When you pass a variable as an argument corresponding to an out or ref parameter, what you are doing is making an alias to the variable. You are not doing anything to the value of the variable. You're making two variables represent the same storage location.

Boxing only happens when a value of a value type is converted to a value of a reference type, and there's no conversion of any kind in your example. The reference type must of course be System.Object, System.ValueType, System.Enum or any interface. Usually it is pretty clear; there's an explicit or implicit conversion in the code. However, there can be circumstances where it is less clear. For example, when a not-overridden virtual method of a struct's base type is called, there's boxing. (There are also bizarre situations in which certain kinds of generic type constraints can cause unexpected boxing, but they don't usually come up in practice.)

Kinetics answered 26/1, 2011 at 16:56 Comment(2)
Thanks for the answer. Is there still a performance hit involved? How does it compare to hits from boxing/unboxing, passing a reference type, or passing a value type?Autoerotic
@Justin: Best advice for any performance question: try it and you'll find out. What you'll probably find is that typically passing a variable by reference is the same cost as passing a reference to an instance of a reference type by reference, which is the same cost as passing a value type of IntPtr size. Keep in mind that pointer-sized parameter passing can be heavily optimized by the jitter if there are available registers.Kinetics
S
8

No boxing, compiler uses the ldloca.s instruction which pushes a reference to the local variable onto the stack (http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.ldloca_s(VS.71).aspx)

.method private hidebysig static void Func() cil managed
{
    .maxstack 2
    .locals init (
        [0] int32 num,
        [1] bool flag)
    L_0000: nop 
    L_0001: ldstr "5"
    L_0006: ldloca.s num
    L_0008: call bool [mscorlib]System.Int32::TryParse(string, int32&)
    L_000d: stloc.1 
    L_000e: ret 
}
Screeching answered 26/1, 2011 at 16:44 Comment(0)
E
6

No, there is no Boxing (required/involved).

When you do Box a variable, changes to the boxed instance do not affect the original. But that is exactly what out is supposed to do.

The compiler 'somehow' constructs a reference to the original variable.

Ethology answered 26/1, 2011 at 16:32 Comment(2)
Thanks for the answer. Do you know if there's still a performance hit involved? How does it compare to the hit from boxing/unboxing, or to passing ordinary parameters?Autoerotic
@Justin, the overhead would depend on circumstance (field or local var) but for a local out will probably be the fastest. You will have to measure for your situation. But it is a micro optimization at best and there are no real alternatives.Ethology
Y
1

There is no boxing; what the out parameter does is specifies that number must be assigned to within the TryParse method. Irrespective of this, it is still treated as an int, not an object.

Yawata answered 26/1, 2011 at 16:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.