ByVal and ByRef

ByVal and ByRef – What is the difference?

ByVal and ByRef are used in a method signature (such as a Sub or Function) to indicate the manner in which the argument is passed from the calling routine to the called routine.  It’s a simple concept on the surface, but has some complex implications.  The following is an attempt to describe these implications using an analogy.

This description demonstrates the different results that can occur when an argument is passed to a Sub and code in the Sub attempts to alter the value of that argument.

If an argument is passed to a Function, the distinction between ByVal and ByRef is not usually significant.  But it is still possible for code in the function to alter the value of the argument, either deliberately or accidentally.  In that case, this description will apply to arguments passed to a Function.

Beware the well-known problems of description by analogy!

I have just finished the agenda for next week’s staff meeting.  I want my work colleague to review it and fix any errors or make any additions that are needed.
I have created a variable and assigned it a value.  I will pass it to a method which will attempt to alter it.

1. The Document as a Value Variable
The document is saved as a file in a known location on the corporate server.
The variable is a simple value variable

1A. Sending a copy of the document to my friend
Value variable passed ByVal

I open Explorer, navigate to the location on the server where the file is saved, open a new e-mail message, drag the file into the message and send the message to my friend. My friend receives the message and saves the attachment to his desktop.
ByVal means that a copy of the variable is sent from the calling routine to the called routine.

My friend makes some changes to the document, saves it, turns off his computer and goes home.  There are no changes to my file.
The copy of the variable is chamged, but has been discarded.  The value of the variable that was passed to the Sub is not changed.

1B. Sending a document to my friend by using an address
Value variable passed ByRef

I open Explorer, navigate to the location on the server where the file is stored, and copy the address of the file from the Explorer address bar.  I paste this address into an e-mail message and send the message to my friend.  My friend opens the message and double-clicks on the address link to open the document.
ByRef means that a reference to the variable is passed from the calling routine to the called routine.

My friend opens the document by clicking on the link I sent.  He makes some changes to the document, saves it, turns off his computer and goes home. When I next open the document the changes are there.
The called routine gets a reference to the original variable..  Therefore, amy changes made are changes to the variable that was passed to the Sub – the value of the variable is changed.

2. The Shortcut as a Reference Variable
A shortcut is the Windows equivalent of a reference to something.

On my desktop there is a shortcut to the document.  I don’t know where on the server (or in the cloud) my document is stored – all I know is that I access my document by double clicking the desktop shortcut.
A reference variable is a variable that refers to an object. Storage of the object (eg, its location) is managed by the run-time system.

2A. Sending a copy of the shortcut to my friend
Reference variable passed ByVal

I open Explorer, navigate to my desktop, create a new e-mail message, drag the shortcut from the desktop onto the message, and send the message to my friend.  My friend receives the message, saves the shortcut to his desktop and double-clicks it.
ByVal means a copy of the variable value is passed to the calling function. For a reference variable, the value of the variable is the reference to the object. So the Sub gets a copy of a reference.

2A(i) Modifying the shortcut
Making changes to the reference variable. You can’t directly change the value of a reference variable (the system manages this).  But you can do so indirectly – you can make the reference variable point to a new or different object.  Since the value of a reference variable is the reference, if you change what it refers to then you are changing its value

My friend decides that the agenda I have written is no good.  He writes a new one (or perhaps he had a draft already prepared) and tells the system to save it somewhere on the server (or in the cloud). He changes his copy of the desktop shortcut to point to his new version of the document and shuts off his machine and goes home. I double-click my desktop shortcut, open the document, and it is unchanged.
The variable that was changed (the shortcut) was a copy that was created for the purpose, and is not available to the calling routine. It has been discarded, and the object it refers to is inaccessible.  (This object still exists, at least until the runtime storage manager does some cleaning up, but there is no variable that refers to it). The variable in the calling routine is not changed.

2A(ii) Modifying the document
Modifying the object that the reference variable refers to.

The shortcut my friend is using is a copy of my shortcut.  If it isn’t changed, then it works the same as mine does.  So, my friend uses the shortcut to access the document, makes a few changes, turns off his computer and goes home.  The changes are in my document.
The called routine uses a copy of the reference variable to access the object.  A copy of a reference variable will refer to the same object as the original, so the object is changed.

2B  Sending a shortcut to my friend by using a shortcut
Reference variable passed ByRef.

This variation requires a small suspension of disbelief, because a desktop PC won’t usually work like this.  But it’s possible to imagine that it does.

I open Explorer, navigate to the desktop where my shortcut is located, and copy the address of the shortcut from the Explorer address bar into a new email message.  I send the message to my friend.  My friend receives the message.  He right clicks in his desktop, selects Create New Shortcut, and pastes the address of my shortcut into his new shortcut. He double-clicks this new shortcut and the agenda document opens.
A reference variable passed ByRef means that the recipient gets a reference to a reference to an object.

2B(i) Modifying the shortcut
Modifying the reference variable (as distinct from modifying the object it refers to )

My friend decides that the agenda I have written is no good.  He writes a new one and lets the system save it somewhere on the server (or in the cloud). He changes his desktop shortcut to point to his new version of the document, but because his desktop shortcut actually points to my desktop shortcut he is actually changing my desktop shortcut to point to his new document!  He shuts off his machine and goes home. I double-click my desktop shortcut, open the document, and it is the changed version.  In fact, it is a different document.  It is, of course, saved at a different location, but since I don’t know where it is located, I don’t notice that.
The variable that was modified in the sub is a reference to the variable in the calling routine.  Because of the way that .Net works, this means that the variable in the calling routine gets changed as a result of changing that reference variable.  So the reference variable in the calling routine now points to the new object that was created in the sub.   The original object has not been changed, but is inaccessible.

2B(ii) Modifying the document
Modifying the object that the reference variable refers to.

The shortcut my friend is using is a reference to my shortcut.  If neither of them is changed, then his shortcut works the same as mine does.  So, my friend looks at the document and makes a few changes, turns off his computer and goes home.  The changes are in my document.
The called routine uses the (double) reference to access the object. Therefore any changes made to that object are changes to the original object in the calling routine.

What is the result?

For a value variable passed ByVal, changes made in the Sub do not affect the original argument
For a value variable passed ByRef, changes made in the Sub do affect the original argument

For a reference variable passed ByVal:
    Changes made to the variable do not affect the original argument
    Changes made to the object it refers to do affect the original object
For a reference variable passed ByRef:
    Changes made to the variable do affect the original argument
    Changes made to the object it refers to do affect the original object

Example Code.

Public Class Form1

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
  Dim I As Integer = 1
  ValUpdateByVar(I)
  MsgBox(“Increment a value variable (1) passed ByVal –> ” & I.ToString)
  Dim J As Integer = 1
  ValUpdateByRef(J)
  MsgBox(“Increment a value variable (1) passed ByRef –> ” & J.ToString)

  Dim myObj1 As TestClass = New TestClass(1)
  RefUpdateByVal(myObj1)
  MsgBox(“Increment reference variable (1) passed ByVal (reference update) –> ” & myObj1.ClassVar.ToString)
  Dim myObj2 As TestClass = New TestClass(1)
  ObjUpdateByRef(myObj2)
  MsgBox(“Increment reference variable (1) passed ByVal (object update) –> ” & myObj2.ClassVar.ToString)

  Dim myObj3 As TestClass = New TestClass(1)
  RefUpdateByRef(myObj3)
  MsgBox(“Increment reference variable (1) passed ByRef (reference update) –> ” & myObj3.ClassVar.ToString)
  Dim myObj4 As TestClass = New TestClass(1)
  ObjUpdateByVal(myObj4)
  MsgBox(“Increment reference variable (1) passed ByRef (object update) –> ” & myObj4.ClassVar.ToString)

End Sub

Public Sub ValUpdateByVar(ByVal Var As Integer)
  Var += 1
End Sub

Public Sub ValUpdateByRef(ByRef Var As Integer)
  Var += 1
End Sub

Public Sub RefUpdateByVal(ByVal Obj As TestClass)
  Obj = New TestClass(Obj.ClassVar + 1)
End Sub

Public Sub ObjUpdateByVal(ByVal Obj As TestClass)
  Obj.ClassVar += 1
End Sub

Public Sub RefUpdateByRef(ByRef Obj As TestClass)
  Obj = New TestClass(Obj.ClassVar + 1)
End Sub

Public Sub ObjUpdateByRef(ByRef Obj As TestClass)
  Obj.ClassVar += 1
End Sub

End Class

Public Class TestClass
Private myVar As Integer

Public Sub New(ByVal Init As Integer)
  myVar = Init
End Sub

Public Property ClassVar() As Integer
  Get
    Return myVar
  End Get
  Set(ByVal value As Integer)
    myVar = value
  End Set
End Property

End Class

Advertisements
  1. Leave a comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s