locked
ByVal Vs. ByRef RRS feed

  • General discussion

  • I have seen a few people in the past confused on the usage of ByRef & ByVal in a Function/Sub's Signature. I figured i would make a simple example that demonstrates the difference of each.

    Option Strict On
    Public Class Form1
        Dim A As Integer = 100
        Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
            ModifyBYREF(A)
            MsgBox(A)
            A = 100
            ModifyBYVAL(A)
            MsgBox(A)
        End Sub
        Sub ModifyBYREF(ByRef int As Integer)
            int = 200
        End Sub
        Sub ModifyBYVAL(ByVal int As Integer)
            int = 200
        End Sub
    End Class


    If you want something you've never had, you need to do something you've never done. If you believe something to be true, then one day you will be called upon to demonstrate that truth.

    Tuesday, June 5, 2012 10:07 PM

All replies

  • Hi Paul,

    Yes, but did you know you can alter a property of a reference type

    whether you pass it ByVal or ByRef?

    Add one Button to a Form to try this please.>>

    Public Class Form1
    
        Public Class ThingWithSomeName
            Private mName As String = "John"
            Public Property Name() As String
                Get
                    Return Me.mName
                End Get
                Set(ByVal value As String)
                    Me.mName = value
                End Set
            End Property
        End Class
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    
            Dim person As New ThingWithSomeName
            MessageBox.Show(person.Name, "Initial name.")
    
            'ByVal test.>>
            ByValTest(person)
            MessageBox.Show(person.Name, "After ByVal...")
    
            'Reset name.>>
            person.Name = "John"
            MessageBox.Show(person.Name, "Reset.")
    
            'ByRef test.>>
            ByRefTest(person)
            MessageBox.Show(person.Name, "After ByRef...")
    
        End Sub
    
        Public Sub ByValTest(ByVal anObject As ThingWithSomeName)
            anObject.Name = "VALerie"
        End Sub
    
        Public Sub ByRefTest(ByRef anObject As ThingWithSomeName)
            anObject.Name = "REFeree Reginald"
        End Sub
    
    End Class




    Regards,

    profile for John Anthony Oliver at Stack Overflow, Q&A for professional and enthusiast programmers

    Click this link to see the NEW way of how to insert a picture into a forum post.

    Installing VB6 on Windows 7

    App Hub for Windows Phone & XBOX 360 developers.

    • Edited by John Anthony Oliver Wednesday, June 6, 2012 12:36 AM Type corrected, thanks Acamar.
    Tuesday, June 5, 2012 10:37 PM
  • Yes, that's a good point, and frequently I do it that way as well. I do not commonly use ByRef, but in some cases it may aid in decreasing the quantity of lines of code  depending on what you're doing.

    If you want something you've never had, you need to do something you've never done. If you believe something to be true, then one day you will be called upon to demonstrate that truth.

    Tuesday, June 5, 2012 10:50 PM
  • Hi again Paul,

    Did you also know that you can change the content of an array for the same reason?

    Try this code.

    If you want to work with a copy of an array then use .Clone()

    that way you can work with a copy of an array and not worry about changing it's content.  :)

    With OPTION STRICT ON the .Clone line needs to be like.>>

    CType(anIntArray.Clone, Integer())

    with OPTION STRICT OFF

    you can have.>>

    anIntArray.Clone

    See below.>>

    '

    Public Class Form1
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    
            Dim testArray() As Integer = New Integer() {1, 2, 3, 4, 5}
            ShowArray(testArray)
    
            'Array contents changed!! >>
            ByValTest(testArray)
            ShowArray(testArray)
    
            'Array contents changed!! >>
            ByRefTest(testArray)
            ShowArray(testArray)
    
            'Array contents NOT changed. >>
            ArrayCloneTest(testArray)
            ShowArray(testArray)
    
        End Sub
    
        Public Sub ByValTest(ByVal anIntArray() As Integer)
    
            For index As Integer = 0 To anIntArray.GetUpperBound(0)
                anIntArray(index) *= 2
            Next
    
        End Sub
    
        Public Sub ByRefTest(ByRef anIntArray() As Integer)
    
            For index As Integer = 0 To anIntArray.GetUpperBound(0)
                anIntArray(index) *= 2
            Next
    
        End Sub
    
        Public Sub ArrayCloneTest(ByVal anIntArray() As Integer)
    
            Dim someIntArray() As Integer = CType(anIntArray.Clone, Integer())
            For index As Integer = 0 To someIntArray.GetUpperBound(0)
                someIntArray(index) *= 2
            Next
    
        End Sub
    
        Public Sub ShowArray(ByVal anIntArray() As Integer)
    
            Dim sb As New System.Text.StringBuilder
            If Not anIntArray Is Nothing Then
                For index As Integer = 0 To anIntArray.GetUpperBound(0)
                    sb.Append(anIntArray(index).ToString & ", ")
                Next
                MessageBox.Show(sb.ToString)
            End If
        End Sub
    
    End Class



    Regards,

    profile for John Anthony Oliver at Stack Overflow, Q&A for professional and enthusiast programmers

    Click this link to see the NEW way of how to insert a picture into a forum post.

    Installing VB6 on Windows 7

    App Hub for Windows Phone & XBOX 360 developers.

    Tuesday, June 5, 2012 10:57 PM
  • Hi Paul,

    In case you did not catch it, I have changed my above code.

    I had the FOR ... NEXT loops starting at 1 instead of zero for the arrays in three

    of the methods, doh!!  I must be tired.  LOL!!




    Regards,

    profile for John Anthony Oliver at Stack Overflow, Q&A for professional and enthusiast programmers

    Click this link to see the NEW way of how to insert a picture into a forum post.

    Installing VB6 on Windows 7

    App Hub for Windows Phone & XBOX 360 developers.

    Tuesday, June 5, 2012 11:15 PM
  • Hi Paul,

    In case you did not catch it, I have changed my above code.

    I had the FOR ... NEXT loops starting at 1 instead of zero for the arrays in three

    of the methods, doh!!  I must be tired.  LOL!!




    Regards,

    profile for John Anthony Oliver at Stack Overflow, Q&A for professional and enthusiast programmers

    Click this link to see the NEW way of how to insert a picture into a forum post.

    Installing VB6 on Windows 7

    App Hub for Windows Phone & XBOX 360 developers.

    It happens to the best of us haha, but yes very interesting. I think there are many times that I should have used ByRef instead of ByVal, but had a case of lazybrain, and ended up with more lines of code.

    If you want something you've never had, you need to do something you've never done. If you believe something to be true, then one day you will be called upon to demonstrate that truth.

    Tuesday, June 5, 2012 11:19 PM
  • You have a typo in the signature of the ByRef test.   But there are actually three scenarios that need to be demonstrated

    1. Passing a value, such as an integer.  This was OP's case
    2. Passing a reference, and changing a property in the referred item - your example.
    3. Passing a reference and changing the reference.  The example below, modified from yours, shows the difference between those last two. That difference becomes important in some specific cases.

    Public Class Form1
    
        Public Class ThingWithSomeName
            Private mName As String = "John"
            Public Sub New(ByVal Name As String)
                mName = Name
            End Sub
            Public Property Name() As String
                Get
                    Return Me.mName
                End Get
                Set(ByVal value As String)
                    Me.mName = value
                End Set
            End Property
        End Class
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    
            Dim person As New ThingWithSomeName("Initial name.")
            Dim aperson As New ThingWithSomeName("Another Initial name.")
            MessageBox.Show(person.Name, "Set.")
            MessageBox.Show(aperson.Name, "Set.")
    
            'ByVal test.>>
            ByValTest(person, aperson)
            MessageBox.Show(person.Name, "After ByVal Property Change...")
            MessageBox.Show(aperson.Name, "After ByVal Instance Change...")
    
            'Reset name.>>
            person = New ThingWithSomeName("Initial name.")
            aperson = New ThingWithSomeName("Another Initial name.")
            MessageBox.Show(person.Name, "Reset.")
            MessageBox.Show(aperson.Name, "Reset.")
    
            'ByRef test.>>
            ByRefTest(person, aperson)
            MessageBox.Show(person.Name, "After ByRef Property Change...")
            MessageBox.Show(aperson.Name, "After ByRef Instance Change...")
    
        End Sub
    
        Public Sub ByValTest(ByVal anObject As ThingWithSomeName, ByVal anotherobject As ThingWithSomeName)
            anObject.Name = "VALerie"
            anotherobject = New ThingWithSomeName("VALerie")
        End Sub
    
        Public Sub ByRefTest(ByRef anObject As ThingWithSomeName, ByRef anotherobject As ThingWithSomeName)
            anObject.Name = "REFeree Reginald"
            anotherobject = New ThingWithSomeName("REFeree Reginald")
        End Sub
    
    End Class

    Wednesday, June 6, 2012 12:31 AM
  • Hi Acamar,

    Thanks for spotting that, I have changed my earlier post.  :)

    I was too busy using COPY & PASTE and not changing the ByVal to ByRef.

    I must be tired!! => Therefore, off to bed. Goodnight everyone ( it is 1:40am in the U.K. ) ....

    or when you eventually get to bed, sleep well.  :)




    Regards,

    profile for John Anthony Oliver at Stack Overflow, Q&A for professional and enthusiast programmers

    Click this link to see the NEW way of how to insert a picture into a forum post.

    Installing VB6 on Windows 7

    App Hub for Windows Phone & XBOX 360 developers.

    Wednesday, June 6, 2012 12:44 AM
  • Since we are talking about ByRef and ByVal, something to note with the later (VS2010?) versions of VB/VS:

    The default, when creating a parameter for a method, is ByVal when it is not explicitly stated.

    Specifically:

        Private Sub DoSomething(a As Integer)
    
        End Sub
    

    and:

        Private Sub DoSomething(ByVal a As Integer)
    
        End Sub
    

    Are exactly the same.




    Stephen J Whiteley

    Wednesday, June 6, 2012 12:13 PM
    Moderator
  • Hi everyone,

    This question is very simple if we look at their full phrase of them.

    ByVal = By value of variable 
    ByRef = By reference of variable

    Ex: 
    Dim Val As Integer = 4

    Let's see method how take a variable
    ByVal : Method will take only value of Val that mean method will copy integer type's value 4 into itself.
    ByRef : Method will take Val into method, not just value of variable that mean method copy reference of Val into itself; so both variable inside and outside method are identical.

    Most misunderstand about this lead from Value type and Reference type, let's see about them.
     Value type : Object of this type will be content by variable ( structure type and almost primitive type).
     Reference type : Object of this type will not be content by variable, only a reference of itself will be content by variable.

    Dim Var = New with { .A = True, .B = 99  }

    Var is only content reference of anonymous type's object not object itself, then when method take variable ByVal or ByRef into itself there will no difference because they are reference to same thing, that is anonymous type's object.

    Unlike Val, it's content object with itself because of Value type; if we not take it into method ByRef, we will only copy a value of Val into method and that make Val's value and the copy's value inside method aren't identical. 
    They may be the same but not identical, don't be confused by them.

    Saturday, June 9, 2012 11:08 PM
  • Try this:

    Draw a button on the form "Button1", and try the following code.

    Try to expect the result before compile and run!

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim a() As Integer = {5}
            Twice(a)
            Me.Text = a(0).ToString
        End Sub

        Private Sub Twice(ByRef n() As Integer)
            For Each q As Integer In n
                q *= 2
            Next
        End Sub

    Thursday, June 28, 2012 7:55 PM
  • I'm not sure what you are getting at... the result will be 5.

    You have decalred a new integer instance "q", assigned it a value from "n()" via the enumerator, operated upon that value, but then did nothing with it.  The value was never pushed back into the array "n()".

    -EDIT-

    Here is the modified routine to yeild 10 as I presume you expected:

    Private Sub Twice(ByRef n() As Integer)
        For count As Integer = 0 To n.Length - 1
            n(count) *= 2
        Next
    End Sub


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"



    Thursday, June 28, 2012 9:10 PM
    Moderator
  • Thanks Reed. I was really confused about my code, and did not know what was going on. Now I know that the iterator in the For Each statement just copies items of the array without affecting them. Thank you.
    Friday, June 29, 2012 8:26 AM