PASSING BY VALUE OR BY REFERENCE

When a variable appears in a program, a location is specified in the computer's memory. When a value is assigned to the variable, the value is stored in that memory location.

When a variable name is passed to a procedure via a parameter list, a new memory location is not created. Rather, the computer goes back to the original memory location designated in the main program in order to obtain the value of the variable. This approach of getting data is referred to as passing the parameter by reference.

Passing by reference is the default method to pass variables in a procedure.

In such cases, changing the value of the parameter in the Sub will result in its value being changed in the memory location specified in the main program.

In some case, you may want to perform operation on a variable in a procedure that change the value of the variable. At the same time, you may want to retain the original value for some other purpose. This can be accomplished by passing the variable using the passing by value method.

You need to enclose the variable within a pair of parentheses when the subroutine is called.

The following example (ValRef.xls) will illustrate the differences between passing by value and passing by reference.

Sub Test()
    x = 1
    y = 0
    MsgBox "Before Call: x = " & x & " and y = " & y
    Call ValRef((x), y)
    MsgBox "After Call: x = " & x & " and y = " & y
End Sub

Sub ValRef(x, y)
    y = x + 1
    x = 0
    MsgBox "Within Sub: x = " & x & " and y = " & y
End Sub

When you run Sub Test, the first Msgbox yields
Before Call: x = 1 and y = 0
After the OK button is clicked, the Sub procedure ValRef is called. Notice that (x)) is passed by value, whereas y is passed by reference. Inside the Sub, y is assigned the value of x + 1. Since x is equal to 1, y is set equal to 2. Then x is assigned a value of 0. The MagBox shows:
Within Sub: x = 0 and y = 2
After OK is clicked, control is transferred back to the calling program, where the final MsgBox is displayed:
After Call: x = 1 and y = 2
Note that because x is passed by value, even though it is changed to 0 in the procedure, its original value of 1 is maintained in the main program. The same is not true for y, which was passed by reference.

If an expression is passed as an argument of a procedure, then that argument is treated as a value argument (passing by value).

For example

Call Example(a + 5, b, c)

The computer first evaluates the expression and places the result in a temporary memory location. The reference for this location is then passed to the procedure as the first argument. As a result, the first argument is treated as a call by value parameter.

Now it should be clear why the parentheses are used to pass a variable by value. In a sense, the parentheses tick the computer into thinking that you are passing an expression.

Besides using the parentheses to place around arguments that are to be passed by value into a function, we can also use the key words, ByVal (or ByRef for reference arguments) in the function heading. The above example can therefore be written as:

Option Explicit
    Sub Test()
    Dim x As Integer, y As Integer
    x = 1
    y = 0
    MsgBox "Before Call: x = " & x & " and y = " & y
    Call ValRef(x, y)
    MsgBox "After Call: x = " & x & " and y = " & y
End Sub

Sub ValRef(ByVal x, ByRef y)
    y = x + 1
    x = 0
    MsgBox "Within Sub: x = " & x & " and y = " & y
End Sub

Here is another example (TestSwitch.xls) of a Sub having reference parameters.

We want to write a Sub procedure having two parameters, say x and y. The purpose of the procedure is to exchange the values in those two parameters.

The original values of x and y (named as a and b in the Excel sheet (called TestSwitch) are contained in cells B4 and B5, respectfully.
The new results for x and y will be written to cells B8 and B9, respectfully.

The programs are:

Sub TestSwitch()
    ' program to test the switch sub procedure
    ' K. Ming Leung, Oct. 16, 2007
    Sheets("TestSwitch").Select
    Range("B4").Select
    a = ActiveCell.Value
    ActiveCell.Offset(1, 0).Select
    b = ActiveCell.Value
    Call switch(a, b)
    ActiveCell.Offset(3, 0).Select
    ActiveCell.Value = a
    ActiveCell.Offset(1, 0).Select
    ActiveCell.Value = b
End Sub

Sub switch(x, y)
    ' first store the value of x in a temporary variable z
    z = x
    ' place the value of y into variable x
    x = y
    ' place the value of z (original value of x) into variable y
    y = z
End Sub

Here is a slightly more complicated example of functions having value and reference parameters:

Option Explicit
Sub testValRef()
    Dim a As Integer, b As Integer, c As Integer
    Dim msg As String
    a = 10: b = 20: c = 30
    msg = "1st message in main: " & a & " " & b & " " & c & Chr(13)
    Call bumble(b, c, a, msg) 'NOTE THE ORDER is b, c, a
    msg = msg & "2nd message in main: " & a & " " & b & " " & c & Chr(13)
    MsgBox msg
End Sub

Sub bumble(ByRef x As Integer, ByRef y As Integer, ByVal z As Integer, _
                        ByRef msg As String)
    msg = msg & "Starting message in bumble: " & x & " " & y & " " & z & Chr(13)
    x = x + 1
    y = y + jumble(4, z, msg)
    z = z + 3
    msg = msg & "Ending message in bumble: " & x & " " & y & " " & z & Chr(13)
End Sub

Function jumble(ByVal x As Integer, ByRef y As Integer, ByRef msg As String)
    msg = msg & "In function jumble." & Chr(13)
    x = y
    y = y - 1
    jumble = x
End Function

The result of the program is:

1st message in main: 10 20 30
Starting message in bumble: 20 30 10
In function jumble.
Ending message in bumble: 21 40 12
2nd message in main 10 21 40
Make sure you can follow every line in the program to see why the output message is the way it is. Keep track of each procedure call and the value and reference parameters that are passed to the procedures.