Page 1 of 1

Reference Types, Value Types, ByVal, ByRef Rate Topic: -----

#1 crepitus  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 85
  • View blog
  • Posts: 383
  • Joined: 08-September 09

Posted 29 October 2009 - 05:22 PM

*
POPULAR

All the Types in .Net are in one of two categories - they are either value types or reference types.

For our purposes we'll simplify things. We'll say that value types are stored in Stack memory, which is fast but limited in size. Compared to reference types, which are stored in Heap memory, which is slower but larger. (Value types can live on the heap too, if they are part of a reference type, but we are just thinking about variables declared locally inside procedures to keep things simple).

A variable is just a label we use as programmers to identify some value on the stack. Let's look at value types, as I've said they live on the stack...

Value types are all fairly small - they don't use much memory. The numeric types are all value types, and they don't take up much size:

Byte - 1 byte
Short - 2 bytes
Integer - 4 bytes
Long - 8 bytes
Single - 4 bytes
Double - 8 bytes
Decimal - 16 bytes

Structures and Enums are also value types. Arrays and Strings are not!

When we declare a value type:
Dim x As Integer = 100


We can think of it like this:
Variable				 Stack					Heap

		"points" to  .-----------.
	x -------------->|   100	 |			   not involved
					 '-----------'

So there's the value 100 living on the stack. It takes up 4 bytes of stack memory as that is the size of an Integer.

Say we declare a value type, but don't assign a value...
Dim y As Integer

Value types always get a default value. For Integer that is a 0:
Variable				 Stack					Heap

		"points" to  .-----------.
	y -------------->|	0	  |			   not involved
					 '-----------'


What happens if we assign one variable to another:
Dim x As Integer = 100
Dim y As Integer = x

This is simple - y gets a copy of the value:
Variable				 Stack					Heap

		"points" to  .-----------.
	x -------------->|   100	 |			   not involved
					 '-----------'

		"points" to  .-----------.
	y -------------->|   100	 |			   not involved
					 '-----------'


This means that x and y are independent. If you now add one to y, you won't change x.

Ok, enough on Value types. Reference types are Objects. They live on the heap. But the sneaky part is that variables still point to something on the stack. That something is a reference to the heap. You can think of it as the heap address where the object is stored.
Button is a reference type, so here we create one and assign it to a variable.
Dim button1 As New Button

Variable				 Stack					Heap 

					 .-----------.			  .---------.
 button1 ----------->|heap	   |------------->| button  | &H1
					 |address &H1|			  | object  |
					 '-----------'			  '---------'


Here I've used an imaginary address &H1 as the heap address. So the variable points to the stack, which has the heap address &H1 which is where the Button lives on the heap.

If we declare, but don't assign an object, by omitting the New part:
Dim button2 As Button

Then we do not create the object on the Heap, but we do have the variable. The variable DOES point to something on the stack too. That something is the null reference - in VB we call it Nothing. Just as Integer has a default value of 0, references have a default value of Nothing.
Variable				 Stack					Heap
					 .-----------.
 button2 ----------->| Nothing   |			  Not involved
					 '-----------'


So, if you tried to do something with button2, you would get the "Object reference not set to an instance blah blah" error. Because, the stack stores the special Nothing value which doesn't point to a Button object on the heap.

Again, lets look at what happens when you assign the value of one object variable to another:

Dim button3 As New Button
Dim button4 As Button = button3


Now - if Button was a value type then we would get a copy. And, in a way, we do get a copy - but it is a copy of the address. So, the net result is that both variables point to the same object on the heap:
Variable				 Stack					Heap
					 .-----------.			  .---------.
 button3 ----------->|address on |------------->| button  |
					 |  heap  &H1|			  |		 |  &H1
					 '-----------'			  '---------'
					 .-----------. ----------------^
 button4 ----------->|address on |
					 |  heap  &H1|			  
					 '-----------'

The result of this is that if you can change the same object using either variable.

If you now decided to say button4 = New Button then button4 would now "reference" the new button, whilst button3 would reference the old button still.


So, what happens when you call a Sub ByVal?

Well, you are sending a copy of the value on the stack. For a value type it is the value, for a reference type it is a reference to an object on the heap...

Value Type ByVal: You send a copy of the value, and the original value will not be changed by changes made in the sub.

' Calling code:
Dim x As Integer = 100
AddOne(x)
' ...
' The Sub
Sub AddOne(ByVal foo As Integer)
  foo+=1
End Sub


Imagine we are in the sub, just as it starts to run. X still exists back in the calling code, and foo has a copy of the value on the stack that x points to:
Variable				 Stack					Heap
					 .-----------.
   x	 ----------->|   100	 |
					 '-----------'
					 .-----------.
  foo	----------->|   100	 |
					 '-----------'


You can see that the two are independent- the variables are pointing to different stack locations. Changes won't stick.

Value Type ByRef: This time the variable in the local sub, used in the sub's signature, will point to the same stack location. So, if you change the value in the sub, you are changing the original.

' Calling code:
Dim x As Integer = 100
AddOne(x)
' ...
' The Sub
Sub AddOne(ByRef foo As Integer)
  foo+=1
End Sub


Variable				 Stack					Heap
					 .-----------.
   x	 ----------->|   100	 | 
  foo	----------->|		   |
					 '-----------'


They are both pointing to the same value on the stack, so changes will stick.

Reference Type ByVal: You send a copy of the Stack contents - i.e. the address to the object on the heap. So, if you alter the object - say be setting a property to a new value, then it is the same object as the one in the calling code - it will be updated.

' Calling code:
Dim button1 As New Button
SetText(button1)
' ...
Sub SetText(ByVal foo As Button)
   foo.Text = "foobar"
End Sub


This should look familiar:
Variable				 Stack					Heap
					 .-----------.			  .---------.
 button1 ----------->|address on |------------->| button  |
					 |  heap  &H1|			  |		 |  &H1
					 '-----------'			  '---------'
					 .-----------. ----------------^
   foo   ----------->|address on |
					 |  heap  &H1|			  
					 '-----------' 


So - they are both referencing the same object. Therefore when the property is changed in the sub, it will be changed in the calling code. Changes Stick.

Reference Type ByRef: Just like the value types, the local variable in the sub will point to the same stack location:
Variable				 Stack					Heap
					 .-----------.			  .---------.
 button1 ----------->|address on |------------->| button  |
   foo   ----------->|  heap  &H1|			  |		 |  &H1
					 '-----------'			  '---------'


Again, if the variables reference the same button object and changes will stick!


So - for Reference types if we pass ByVal or ByRef the object in the calling code can be modified. Is there a difference!?!?!

YES (and this is an interview question!):

Consider:

' Calling code
Dim button1 As New Button
Bar(button1)
' ...
Sub Bar(ByVal foo As Button)
   foo = New Button
End Sub


Here we are doing something different - we are not altering the object on the heap by setting a property, but assigning a completely new object to the variable. This is the result when execution has just passed the line foo = New Button
Variable				 Stack					Heap

					 .-----------.			  .---------.
 button1 ----------->|address on |------------->| button  | &H1
					 |   heap &H1|			  | object  |
					 '-----------'			  '---------'
					 .-----------.			  .---------.
  foo	----------->|address on |------------->| button  | &H2
					 |   heap &H2|			  | object  | 
					 '-----------'			  '---------'


Here the change hasn't stuck. The foo variable that is local to the sub references the new Button at the new address, but the old button1 variable remains the same, pointing to address &H1 which has the original Button object.

Finally... (congratulations on getting this far BTW)
Consider the ByRef version of that:

' Calling code
Dim button1 As New Button
Bar(button1)
' ...
Sub Bar(ByRef foo As Button)
   foo = New Button
End Sub


Variable				 Stack					Heap

					 .-----------.			  .---------.
 button1 ----------->|address on |			  | button  | &H1
  foo	----------->|   heap &H2|---		   | object  |
					 '-----------'   |		  '---------'
									 |		  .---------.
									 |--------->| button  | &H2
												| object  | 
												'---------'


foo and button1 both point to the same stack address. So once a New Button has been assigned, they both reference the New Button at &H2. The Button object at &H1 is no longer referenced by any variable and it is therefore freed for garbage collection.

See:
MSDN: Passing Arguments by Value and by Reference
C# Heap(ing) Vs Stack(ing) in .Net - the non-simple way to explain it all, and more, but in C#...

Is This A Good Question/Topic? 5
  • +

Replies To: Reference Types, Value Types, ByVal, ByRef

#2 AdamSpeight2008  Icon User is offline

  • MrCupOfT
  • member icon


Reputation: 2257
  • View blog
  • Posts: 9,445
  • Joined: 29-May 08

Posted 29 October 2009 - 05:53 PM

Fantastic Tutorial.
Was This Post Helpful? 0
  • +
  • -

#3 snikmotnairb  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 13
  • View blog
  • Posts: 70
  • Joined: 02-May 08

Posted 05 November 2009 - 09:00 AM

Very nice explanation crepitus!
Was This Post Helpful? 0
  • +
  • -

#4 bly  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 8
  • Joined: 24-March 09

Posted 07 July 2010 - 05:32 PM

Thanks a really great tutorial
Was This Post Helpful? 1
  • +
  • -

#5 Guest_simon*


Reputation:

Posted 06 September 2010 - 04:48 AM

"For our purposes we'll simplify things"

I got a few questions, about what perhaps is simplified (?)

Does a reverence type passed ByRef actually point to the same stack address? Or does it have a different stack address that points to the sending variables stack address?

I would like to understand exactly what happens when you say x = New ....
Does it happen something different if x is a class member object or passed into a method as a ByVal or ByRef reference ?

cheers
Was This Post Helpful? 0

#6 cscchee  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 23-April 13

Posted 23 April 2013 - 07:54 AM

csc chee, on 23April2013 - 10:52 PM, said:

Great Tutorial. Thank you so much for sharing! :)

Was This Post Helpful? 0
  • +
  • -

#7 JDGiants  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 9
  • Joined: 18-October 11

Posted 10 August 2014 - 01:45 PM

Great explanation - thank you!
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1