13

I am struggling to understand pass by value and pass by reference in VB6. I understand these concepts fully in Object Oriented programming languages like .NET and Java (I realise that Java doesn't have pass by reference). Have a look at the code below:

Private Sub Form_Load()

Dim Test As Integer
Test = 1
TestFunction Test 'line 5
MsgBox (Test)

End Sub

Private Sub TestFunction(ByVal i As Integer)
    i = i + 1
End Sub

When I put brackets around Test on line 5, then the message box prints 1 as I would expect. Now have a look at the code below:

Private Sub Form_Load()

Dim Test As Integer
Test = 1
TestFunction Test 'line 5
MsgBox Test

End Sub

Private Sub TestFunction(ByRef i As Integer)
    i = i + 1
End Sub

The message box prints 2 as I would expect. However, if you add brackets to line 5 then the message box prints 1 as I would not expect. It appears that the calling function can pass by value even if the variable defined in the called function is ByRef. It appears not to be the case vice versa, i.e. if the called function has a signature with a variable defined as ByVal then it will always be ByVal (even if there are no brackets around the variable in the calling function). What is the thinking behind this in VB6? I realize that this is a basic question in VB6 but it has confused me. I have read the MSDN documentation and I realize that this is all true, however it does not explain the reasoning behind it.

Mathieu Guindon
  • 69,817
  • 8
  • 107
  • 235
w0051977
  • 15,099
  • 32
  • 152
  • 329

2 Answers2

21

This is a classic gotcha in VB6. It is explained in the VB6 manual. In this code below, VB6 treats the argument as an expression (Test) rather than a variable reference

TestFunction (Test)

In order to pass a reference to the variable either omit the brackets or use the legacy Call statement (which requires brackets)

TestFunction Test
Call TestFunction(Test)

VB6 allows you to pass expressions to ByRef arguments even if the method changes them. Eg you can write

TestFunction (Test + 2)

The compiler creates a temporary copy and passes that by reference. VB.Net uses brackets in a similar way.

You can also get the compiler to create temporary copies if TestFunction takes two arguments like this:

TestFunction (one), (two)

And you can get temporary copies even with Call if you double your brackets, adding an extra unecessary pair:

Call TestFunction((Test))
MarkJ
  • 30,070
  • 5
  • 68
  • 111
  • Thanks. This is useful. What is the purpose of the Call function? Does this mean that the variable passed will never be treated as an expression? I am surprised by this as I have never really thought about it before. Also, if there are more than one variables to pass, then I assume that you can't include an expression? – w0051977 Apr 21 '12 at 20:34
  • 2
    I'm not sure how this is a "gotcha" since it is documented, intentional behavior. The Call keyword is legacy and deprecated, going back to early MS Basics. It was there to ease porting old programs forward. – Bob77 Apr 22 '12 at 03:56
  • 2
    The `Call` keyword has no bearing one whether or not arguments are treated as expressions. It simply uses parentheses as the way to pass arguments and so a single pair of parentheses has a different meaning. But parentheses around an argument produces an expression just as without the `Call` keyword. – Jonathan Wood Apr 23 '12 at 14:02
  • 4
    @Bob I call it a gotcha because it is well-known as a language pitfall, tricky to understand and apt to trap newbies. That's my understanding of gotcha. Mirriam- Webster dictionary: *gotcha* an unexpected usually disconcerting challenge, revelation, or catch. The intention and documentation (which I've linked) aren't enough in this case to stop it being a gotcha. – MarkJ Apr 23 '12 at 19:34
  • Good gourd, on that basis ("confusing to a newbie") you can justify calling anything in any language a "gotcha." Sorry, I just don't buy it, and I think it is unnecessarily negative. – Bob77 Apr 23 '12 at 21:42
  • 3
    @Bob No, I don't believe my words justify calling anything a gotcha. Only things that are *frequently* misunderstood. I hope I am providing a little friendly criticism of the language rather than being negative (I like VB!). Mostly though I'm trying to encourage the learner by telling them they are not alone in finding this difficult. That is important in teaching. – MarkJ Apr 23 '12 at 21:57
  • 1
    The specific thing which makes this a "gotcha" is that you can remove the `call` and it will subtly change the behavior. The parens / brackets have different usage with and without that keyword. The accompanying slight change in spacing is quite unlikely to be noticed, nor understood by a less experienced VB programmer. – StayOnTarget May 19 '20 at 14:04
7

Enclosing any expression within parentheses causes that expression to be evaluated first before doing anything else, even when that expression is only a single variable. In your case, the result of that expression is then passed as an argument.

So, you are in fact passing the argument by reference. But the argument you are passing is the result of the expression and not the original variable. This is why the original variable does not get updated.

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466