How to Pass Arguments Efficiently in Visual Basic
This is from Microsoft Excel 2000 Visual Basic Help, with changes and additions.
All arguments are passed to procedures by reference, unless you specify otherwise. This is efficient because all arguments passed by reference take the same amount of time to pass and the same amount of space (4 bytes) within a procedure regardless of the argument’s data type.
You can pass an argument by value if you include the ByVal keyword in the procedure’s declaration. Arguments passed by value consume from 2 to 16 bytes within the procedure, depending on the argument’s data type. Larger data types take slightly longer to pass by value than smaller ones. Because of this, String and Variant data types generally should not be passed by value.
Passing an argument by reference uses the original variable. Changes to the argument within the procedure are returned to the original variable. Thus, a Sub or Function procedure can pass many changed values back to the calling procedure.
Passing an argument by value copies the original variable. Changes to the argument within the procedure are not returned to the original variable. For example:
' Demonstration of ByVal to prevent changing calling variable, using Factorial Function:
Option Explicit
Function FactorialByVal(ByVal MyVar As Long) ' Correct Function declaration.
MyVar = MyVar - 1
If MyVar = 0 Then
FactorialByVal = 1
Exit Function
End If
FactorialByVal = FactorialByVal(MyVar) * (MyVar + 1)
End Function
Function Factorial(MyVar As Long) ' Function declaration without ByVal.
MyVar = MyVar - 1
If MyVar = 0 Then
Factorial = 1
Exit Function
End If
Factorial = Factorial(MyVar) * (MyVar + 1) ' Passes by reference
' Factorial = Factorial((MyVar)) * (MyVar + 1) ' To fix: Pass by value
End Function
Sub Demo() ' Call Factorial with a variable S.
Dim S As Long
S = 5
Debug.Print "S="; S ' Displays 5 (starting value).
Debug.Print "Factorial ByVal="; FactorialByVal(S) ' Displays 120 (the factorial of 5)
Debug.Print "S="; S ' Displays 5 (unchanged due to ByVal).
Debug.Print "Factorial="; Factorial(S) ' Erroneously Displays 1
Debug.Print "S="; S ' Displays 0 (altered by function).
End Sub
Function FactorialByVal includes ByVal in the function declaration. The second Print statement displays 120, the factorial of 5. The third Print statement shows that S is unchanged due to ByVal. This is because changes to MyVar are not fed back to variable S.
Function Factorial omits ByVal from the function declaration. The final two Print statements display 1 and 0. This is because MyVar would then refer back to variable S, which is reduced by 1 until it equals 0.
Because ByVal makes a copy of the argument, it would allow you to pass a variant to the FactorialByVal function above. You can’t pass a variant by reference if the procedure that declares the argument is another data type.
Using ByVal in the called procedure’s declaration means that the procedure forces passing by value. Alternatively, the calling procedure can pass by value. We do this by enclosing each such variable in parentheses. Thus, the calls Factorial((MyVar)), or Call MySub(A$, (B#), (C#)) would mean that the values of MyVar, B#, and C# are passed to the called procedures. Even without any ByVal keywords in the called procedures, changed values would not pass back to calling procedures. Meanwhile, if MySub did not have a ByVal before its first parameter, it would pass any changes in A$ back to the calling procedure.
See also: Visual Basic conceptual topics.