Question ByRef vs ByVal

Adagio

Well-known member
Joined
Dec 12, 2005
Messages
162
Programming Experience
Beginner
From what I understand, this is how it works:

ByRef (a.k.a. By Reference) points to where the object is in the memory. Any changes made to the object sent ByRef should change the values of the original object
ByVal (a.k.a. By Value) points to a copy of the object. Any changes made to the object shouldn't change anything in the original object

Let's make an example:

VB.NET:
Private Sub FormLoad()
Dim a As String = "A"
Dim b As String = "B"

MsgBox(a & " - " & b) ' This shows "A - B"

ChangeProperty(a)
ChangeRefProperty(b)

MsgBox(a & " - " & b) ' This shows "A - Buuuu"
End Sub

Private Sub ChangeProperty(ByVal b As String)
        b = "Baaaa"
End Sub

Private Sub ChangeRefProperty(ByRef b As String)
        b = "Buuuu"
End Sub


This shows exactly how I understand the difference between ByVal and ByRef
But if we instead of using simple objects as Strings, there's no difference between ByVal and ByRef anymore. Just take a look at this example:

VB.NET:
Private Sub FormLoad()
  Dim a As New Bacon
  Dim b As New Bacon
  a.NewProperty = "A"
  b.NewProperty = "B"

  MsgBox(a.NewProperty & " - " & b.NewProperty) ' This shows "A - B"

  ChangeProperty(a)
  ChangeRefProperty(b)

  MsgBox(a.NewProperty & " - "& b.NewProperty) ' This shows "Baaaa - Buuuu"
End Sub

Private Sub ChangeProperty(ByVal b As Bacon)
        b.NewProperty = "Baaaa"

End Sub


Private Sub ChangeRefProperty(ByRef b As Bacon)
        b.NewProperty = "Buuuu"

End Sub


Private Class Bacon

        Private newPropertyValue As String
        Public Property NewProperty() As String
            Get
                Return newPropertyValue
            End Get
            Set(ByVal value As String)
                newPropertyValue = value
            End Set
        End Property

End Class

The second messagebox shows Baaaa - Buuuu instead of the expected A - Buuuu... but why is that? Apparently ByVal and ByRef does exactly the same thing. It seems like it sends the reference to the object when using ByVal, instead of making a new object
Anyone here who can tell me why this is?
 
A variable is a named memory location, it holds a value for value types or a memory address aka reference for reference types. ByVal parameters make a copy of the value or reference that was passed, just like declaring a new variable and assigning it something, so in the latter case a new reference is created pointing to the same object the original variable was pointing to. With ByRef a new variable is not created, the same variable aka memory location that was passed in is also used within the method. So for reference types a ByRef parameter only matters if you need to assign a new instance, if it was ByVal and you assigned a new instance in the method it would not be reflected in the original variable.
 
ByRef and ByVal behave the same if you alter something about the object, such as appending some new characters to a StringBuilder

Where the difference comes in is if you swap the object for another one entirely, that's when a ByRef variable will "change" and a ByVal one doesnt

The reason is, as John points out, that with ByVal a copy of the pointer is passed, the copy is changed and the change is lost when the copy goes out of scope

Here is a better example code:
VB.NET:
  Sub ChangeContentsByVal(ByVal sb as StringBuilder)
    sb.Append("ChangeContentsByVal")
  End Sub

  Sub ChangeContentsByRef(ByRef sb as StringBuilder)
    sb.Append("ChangeContentsByRef")
  End Sub

  Sub ChangeReferenceByVal(ByVal sb as StringBuilder)
    sb = New StringBuilder("ChangeContentsByVal")
  End Sub

  Sub ChangeReferenceByRef(ByRef sb as StringBuilder)
    sb = New StringBuilder("ChangeContentsByVal")
  End Sub


...

Dim sb As New StringBuilder("Original")


ChangeContentsByVal(sb)
ChangeContentsByRef(sb)
ChangeReferenceByVal(sb)
ChangeReferenceByRef(sb)
Use the debugger to investigate the sb at each step


Strings are a poor choice for demonstrating this, because their contents are immutable. The onyl thing you can do is change the reference to a whole new string, which loses the subtlety of the ChangeContentsByXXX point

It's worth noting that ByRef is almost never needed within VB. If you need to return multiple values, create a class and use a function. It is most often used when communicating with other processes (databases where stored procedures send back multiple values)

Even in these cases, consider using e.g. a row cursor to return multiple values. Giving sections of code the ability to swap an object for another one entirely can cause some serious headaches

Anyone here who can tell me why this is?

Youre getting confused into thinking that ByVal causes an entire copy of the whole object itself to be created. The only thing that is ever copied is the pointer(reference) to the object. The "a As Bacon" object only ever existed once:

Dim a As New Bacon

Dim a_copy as Bacon = a

VB.NET:
ascii art:

a ----> [bacon object in memory] <---- a_copy

Now you have 2 copies of a pointer to one object. This is what ByVal did.
 
Last edited:
Back
Top