Boxing and Unboxing of Value-Types when passed to a method call

A

ALI-R

Hi All,
First of all I think this is gonna be one of those threads :) since I have
bunch of questions which make this very controversial:-0)
Ok,Let's see:

I was reading an article that When you pass a Value-Type to method call
,Boxing and Unboxing would happen,Consider the following snippet:
int a=1355;
myMethod(a);
......
void myMethod(int b);

Can somebody describes what exactly happens in the stack and (probably in
the heap) when this code is executed?

Thanks for your time in advance,I will ask my other questions as we go
further with this thread.

Cheers,
Raza Alirezaei
 
M

Mattias Sjögren

I was reading an article that When you pass a Value-Type to method call
,Boxing and Unboxing would happen,Consider the following snippet:
int a=1355;
myMethod(a);
.....
void myMethod(int b);


There's no boxing going on here. It would only happen if the parameter
type was object, or an interface implemented by the argument.




Mattias
 
A

ALI-R

Ok,Let's change it in this way:

int a=1355;
myMethod(a);
.....
void myMethod(Object b);


Now ,boxing and unboxing is happned or not?

Cheers,
Reza Alirezaei
 
G

Guest

Boxing is the process of treating a value type as a reference type. See:
http://msdn.microsoft.com/library/d.../en-us/csref/html/vclrfboxingconversionpg.asp

object obj = Int32.MaxValue; // The int value is "boxed" to a reference type
int i = (int)obj; // The int held by obj is "unboxed" with the cast

I of course don't know how boxing is actually implemented in the CLR, but
one possibility I suppose is that a temporary class is created with a member
of the value type, and its reference (pointer) can then be passed around as
with any other reference type.

Of note is that the boxed value does not point at the original value, as:

//////////////////////////////////////////////////

struct T
{
public int Value; // default = 0
};

class C
{
static void Main()
{
T t = new T();
object obj = t;

t.Value += 1;

Console.WriteLine("Original value = {0}", t.Value);
Console.WriteLine("Object value = {0}", ((T)obj).Value);
}
};

//////////////////////////////////////////////////

This code prints:

Original value = 1
Object value = 0

If the boxed object pointed at the original value then the object's value
would also be 1.

- KH
 
B

Bruce Wood

Mattias is correct. Here are some more details. In your code snippet:

int a=1355;
myMethod(a);
......
void myMethod(int b)
{ ... }

What would happen in C# is the same thing that would happen in any
other language: the compiled program will place a 32-bit integer on the
stack and invoke myMethod(). No boxing. No unboxing. However, consider
the following example:

int a = 1355;
myMethod(a);
....
void myMethod(object o)
{ ... }

In this case, myMethod is expecting an object, which is a reference
type, not a value type. For a reference type, the method is expecting a
pointer on the stack, or in C# parlance, a _reference_ to an object.
So, the myMethod(a) call would do the following:

o "Box" the value of a: create an Int32() value on the heap and
initialize it to 1355.
o Call myMethod with a reference to the new Int32() object.

The call _has_ to do this in order to pass a consistent argument to
myMethod(). In other words, myMethod() has to know what it's receiving,
and since a reference to an instance on the heap is the "lowest common
denominator," the compiled program "boxes" (allocates an object on the
heap for) the value type being passed in. This _doesn't_ happen in your
code snippet because both the caller and the method agree that what's
being passed is always an int, never anything else, so there's no need
to reduce it to an object.

As well, consider the following snippet:

int a = 1355;
myMethod(a);
....
void myMethod(IComparable o)
{ ... }

This time, IComparable is an interface, not a class, but the effect is
the same: since IComparable things can be value or reference types, and
so to pass a consistent thing to myMethod(), the running program boxes
the integer and passes it as a reference to an Int32 object instance.

Note that all of this is more important when considering the collection
structures provided by the .NET framework. Before V2.0 and generics
comes along, if you put a bunch of integers in an ArrayList (or a
Hashtable, or a SortedList, or a...) then all of the integers (or
doubles, or booleans, or ...) will be boxed before they're put into the
ArrayList. They have to be, because an ArrayList is defined as being a
collection of _objects_, and so is designed to hold object references,
not hold value types like integers directly.

This is where _unboxing_ comes in: when you place an integer in an
ArrayList, it must be made into an object instance reference, and so
space is allocated on the heap, and a pointer to that space is placed
in the ArrayList ("boxing"). When you ask to retrieve an integer from
the ArrayList:

int a = (int)myArrayList;

your compiled program follows the object reference stored at
myArrayList, fetches the value from within the object on the heap,
and assigns that value to a (unboxing).

Much of the need for boxing and unboxing goes away with the
introduction of generics in V2.0, but that's fodder for another post.
 
A

ALI-R

Thanks for your nice replies ,specifically the one for Bruce wood.
I got what I wanted from the First question.I'm going to summorize it and
move on the second question:

Again cosidering my snippet:
Here is what happens,tell me if I am wrong:
"b" (Reference to the boxed "a" which is on the heap) is created on the
stack and it points to boxed "a" object on the heap.Infact what we have on
the heap is only a shallow copy of original "a" with the same data but
completely different thing(as we can change the value of original "a" and
nothing would happen to Boxed "a" object on the heap).

ok ,Moving on.I'd like to change my code a bit more:


I assume that there is no boxing and unboxing invovled here ,but I'd like to
know the space allocation on stack and heap for this guy.

More changes in the next thread,
Thanks for monitoring this thread.

Reza Alirezaei

I'd like to change the snippet a bit to add my second question:
 
G

Guest

Mattias Sjögren said:
There's no boxing going on here. It would only happen if the parameter
type was object, or an interface implemented by the argument.

Also ValueType, although I can't think of any reason why you'd want to do
that ;-)
 
B

Bruce Wood

I believe that this would act the same as passing an int as int* in C.
To wit:

Whether there is heap space allocated depends very much on where the
"int a = 1355" appears. If it is a local variable in a method then it
will be on the stack; if it is a class member then it will allocated
within the class data area allocated on the heap; if it is a struct
member then it will be allocated within the struct data area either on
the stack or the heap, depending on whether the struct is a local
variable or a class member.

myMethod will be passed a pointer to (reference to) the memory location
at which the integer called "a" is stored. The pointer (reference) will
be allocated on the stack, because it is a method argument. Modifying b
within myMethod will modify a, because b and a refer to the same memory
location.

No boxing or unboxing involved; the reference passed to myMethod points
directly to the integer.
 
A

ALI-R

Let's pretend that int a=1355 is a local variable and it is in the stack.
So you mean by executing <<MyMEthod(ref a)>> another space called "b" is
created in the **STACK** which holds a reference to another space in the
**STACK** called "a". right?

cheers,
REza Alirezaei
 
A

ALI-R

I think I made a mistake in the last posting :

Method parameters(here "b") count as local variables too, but if they are
declared with the ref modifier, they don't get their own slot, but share a
slot with the variable used in the calling code(here "a").

cheers
Reza Alirezaei
 
B

Bruce Wood

Yes, that is my understanding.

After all, all method arguments _must_ be allocated on the stack,
whether they are references to items on the heap, references to other
items on the stack, or values being passed directly. So, by definition
"b" _must_ be on the stack.

However, we also know that "b" is a direct reference to the memory
location called "a" that is holding the value 1355, which, because it's
a local variable, is also on the stack.

Therefore, the argument to myMethod, b, is a reference held on the
stack that refers to another stack location called "a" that holds the
int value. The heap is not involved at all in this case.

If, on the other hand, a method argument is a reference _type_ (as
opposed to a reference _parameter_: read Jon Skeet's excellent article
to clear up any confusion between the two) and you pass a value, thus
requiring boxing, the compiler must create a temporary object to hold
the value (it must "box" the value), and in so doing you might think
that it has two options: it could create the temporary object in the
heap and pass a reference to that to the method, or you might imagine
it could create the temporary object on the stack, if it (the compiler)
could know that the boxed value will be thrown away immediately as the
method returns.

However, the compiler can't know that, because the method (for example
ArrayList.Add) might take that object reference and copy it somewhere
(such as in an ArrayList data structure), and so deallocating the
temporary, boxed copy upon return would be disastrous.

For this reason boxes for value types are always created in the heap:
the compiler never knows if you're going to grab a copy of the
reference and store it somewhere, so it defers the deallocation problem
to the garbage collector.
 
A

ALI-R

Considering this :

I'm afraid I can't agree with you in this sentence:
Therefore, the argument to myMethod, b, is a reference held on the
stack that refers to another stack location called "a" that holds the
int value. The heap is not involved at all in this case.

What I say is this:
"b" is not a seperate entity and it dose use the storage location of the
variable specified on the invocation (here is "a") -According to Skeet's
excellent article:)
having accepted this there is no need for temporary objects then.

Cheers,
Reza
 
B

Bruce Wood

A little confusion here, where you say that "if they are declared 'ref'
they don't get their own slot."

Yes they do. It is just that the slot is for a reference, which is a
special type of value that points to another value. All the "ref"
keyword on an int argument does is tell the method, "this value is an
address that points to a value of type int that is stored elsewhere."
It also tells the caller that rather than copying the int value from
one stack location (where it is stored) to another (where the method
argument is stored), it should place a reference to the int value on
the stack as the method argument.

Every method argument* gets a "slot" on the stack, although the "slots"
may vary in size depending upon the type of the argument. Arguments to
parameters marked "ref" are merely slots for references, rather than
slots for values.

*If you use the "params" keyword then you may have arguments that do
not have individual slots on the stack. The "params" keyword really
does fundamentally change the way that arguments are passed into a
method.
 
B

Bruce Wood

Ah, I see what you mean. Well, that's more a matter of point of view.
It depends upon whether you consider the name "b" to refer to "the
thing pointed to be the reference that was passed into my method", in
which case "the reference" that is on the stack has no name, or you
consider the name "b" to refer to "a reference to an int that is
magically dereferenced whenever the name 'b' is mentioned". Being an
old C hack, I tend to think of it in the latter way, but I admit that
the former is equally valid. This will change the interpretation of
some of the things I've said in other posts. My apologies for any
confusion.

So, yes, you could see "b" as just a synonym for "a" and therefore it
has no special stack space of its own, and the reference on the stack
that was passed into "myMethod" as an artifact of the language that has
no name.
 
A

ALI-R

Excellent monitoring ,Excellent Cooperation ,Hopefully this thread could
help those people (like me;-)) who still have the confusion about how the
parameter passing is handled in C# and Generally what's the diference
between ValueTypes VS ReferenceTypes in C#.

I'd like to point to some nice sentences from I extracted from Skeet's
excellent article:

1)A reference type is a type which has as its value a reference to the
appropriate data rather than the data itself.
Remember though that the value of a reference type variable is always a
reference not the actual data




2)While reference types have a layer of indirection between the variable and
the real data, value types don't. Variables of a value type directly contain
the data

3)Saying that "value types go on the stack, reference types go on the heap"
is an incorrect oversimplification (As Jon Skeet - <[email protected]>
said here and in his excellent article). It depends on the context in which
it is declared:
a.. Each *local variable (ie one declared in a method) is stored on the
stack. That includes reference type variables - the variable itself is on
the stack, but remember that the value of a reference type variable is only
a reference (or null), not the object itself (Object is on the heap).
*Method parameters count as local variables too, but if they are declared
with the ref modifier, they don't get their own slot, but share a slot with
the variable used in the calling code.
b.. Instance variables for a reference type are always on the heap. That's
where the object itself "lives".
c.. Instance variables for a value type are stored in the same context as
the variable that declares the value type. The memory slot for the instance
effectively contains the slots for each field within the instance. That
means (given the previous two points) that a struct variable declared within
a method will always be on the stack, whereas a struct variable which is an
instance field of a class will be on the heap.
Every static variable is stored on the heap, regardless of whether it's
declared within a reference type or a value type. There is only one slot in
total no matter how many instances are created.

4)Saying that "In method calls objects are passed by reference by default
" is not true

5)Reference parameters don't pass the values of the variables used in the
function member invocation - they use the variables themselves. Rather than
creating a new storage location for the variable in the function member
declaration, the same storage location is used, so the value of the variable
in the function member and the value of the reference parameter will always
be the same


6) What is the difference between passing a value object by reference and a
reference object by value?Consider the following code?
Read skeet's article at http://www.pobox.com/~skeet/csharp/memory.html


Hope this helps,
Reza Alirezaei
 
A

Abubakar

Quoting from ms-help://MS.NETFrameworkSDKv1.1/csref/html/vclrfNewOpPG.htm:
"Value-type objects such as structs are created on the stack, while
reference-type objects such as classes are created on the heap."

"oversimplification" maybe true but please atleast dont say its "incorrect"!

I didnt go into explanation. It was to give an idea to his:
Can somebody describes what exactly happens in the stack and (probably in
the heap) when this code is executed?

and if Ali wants the explanation, than your article does a good job and he
should read that also besides the help in sdk.

Ab [ not an mvp :) ].
 
J

Jon Skeet [C# MVP]

Abubakar said:
Quoting from ms-help://MS.NETFrameworkSDKv1.1/csref/html/vclrfNewOpPG.htm:
"Value-type objects such as structs are created on the stack, while
reference-type objects such as classes are created on the heap."

I can produce other incorrect quotes from MSDN if you want. It's not
perfect.
"oversimplification" maybe true but please atleast dont say its "incorrect"!

It is - structs are created on the stack *and* on the heap.
I didnt go into explanation. It was to give an idea to his:

and if Ali wants the explanation, than your article does a good job and he
should read that also besides the help in sdk.

But you gave the misleading impression that value types only ever
"live" on the stack. That's simply not true.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top