How to: Protect a Procedure Argument Against Value Changes (Visual Basic)


Updated: July 20, 2015

For the latest documentation on Visual Studio 2017, see Visual Studio 2017 Documentation.

If a procedure declares a parameter as ByRef, Visual Basic gives the procedure code a direct reference to the programming element underlying the argument in the calling code. This permits the procedure to change the value underlying the argument in the calling code. In some cases the calling code might want to protect against such a change.

You can always protect an argument from change by declaring the corresponding parameter ByVal in the procedure. If you want to be able to change a given argument in some cases but not others, you can declare it ByRef and let the calling code determine the passing mechanism in each call. It does this by enclosing the corresponding argument in parentheses to pass it by value, or not enclosing it in parentheses to pass it by reference. For more information, see How to: Force an Argument to Be Passed by Value.

The following example shows two procedures that take an array variable and operate on its elements. The increase procedure simply adds one to each element. The replace procedure assigns a new array to the parameter a() and then adds one to each element. However, the reassignment does not affect the underlying array variable in the calling code.

  Public Sub increase(ByVal a() As Long)
      For j As Integer = 0 To UBound(a)
          a(j) = a(j) + 1
      Next j
  End Sub

    Public Sub replace(ByVal a() As Long)
        Dim k() As Long = {100, 200, 300}
        a = k
        For j As Integer = 0 To UBound(a)
            a(j) = a(j) + 1
        Next j
    End Sub

    Dim n() As Long = {10, 20, 30, 40}
    Call increase(n)
    MsgBox("After increase(n): " & CStr(n(0)) & ", " & 
        CStr(n(1)) & ", " & CStr(n(2)) & ", " & CStr(n(3)))
    Call replace(n)
    MsgBox("After replace(n): " & CStr(n(0)) & ", " & 
        CStr(n(1)) & ", " & CStr(n(2)) & ", " & CStr(n(3)))

The first MsgBox call displays "After increase(n): 11, 21, 31, 41". Because the array n is a reference type, replace can change its members, even though the passing mechanism is ByVal.

The second MsgBox call displays "After replace(n): 11, 21, 31, 41". Because n is passed ByVal, replace cannot modify the variable n in the calling code by assigning a new array to it. When replace creates the new array instance k and assigns it to the local variable a, it loses the reference to n passed in by the calling code. When it changes the members of a, only the local array k is affected. Therefore, replace does not increment the values of array n in the calling code.

The default in Visual Basic is to pass arguments by value. However, it is good programming practice to include either the ByVal or ByRef keyword with every declared parameter. This makes your code easier to read.

Procedure Parameters and Arguments
How to: Pass Arguments to a Procedure
Passing Arguments by Value and by Reference
Differences Between Modifiable and Nonmodifiable Arguments
Differences Between Passing an Argument By Value and By Reference
How to: Change the Value of a Procedure Argument
How to: Force an Argument to Be Passed by Value
Passing Arguments by Position and by Name
Value Types and Reference Types