ByRef and ByVal in VBScript
Eric Lippert has a great article on using parentheses in VBScript:
What do you mean "cannot use parentheses?" Your example illustrates one of the points he mentions, namely: enclosing a ByRef
argument in parentheses passes it as ByVal
.
In short, parentheses in VBScript subroutine calls can be put not only around the argument list, but also around individual arguments (in which case they are forced ByVal
). And VBScript only expects the argument list be enclosed in parentheses if the Call
keyword is used. Since the IncrementByRef(Num)
call doesn't use the Call
keyword, VBScript treats parentheses as applied to the subroutine argument and thus passes it ByVal
instead of ByRef
.
Confusing, but that's the way it works.
It's a feature, not a bug:
http://msdn.microsoft.com/en-us/library/ee478101.aspx
A ByRef parameter is passed by value if the argument is enclosed in parentheses and the parentheses do not apply to the argument list.
The parentheses apply to the argument list if one of the following is true:
The statement is a function call that has an assignment to the returned value.
The statement uses the Call keyword. (The Call keyword can optionally be used for a subroutine call, or for a function call without an assignment.)
So try using the Call keyword or having it return a value.
IncrementByRef Num
calls and increments using a reference to Num
IncrementByRef (47 + 3)
calls and increments using a reference to "50". Which is discarded on exit.
IncrementByRef (Num)
IncrementByRef (Num + 18)*5
IncrementByRef Cint("32")
Are all legal in BASIC, as they were in FORTRAN. Notoriously, in one early FORTRAN, passing by ref allowed you to change the value of expressions like
5
Which was sufficiently confusing that only very small, early FORTRAN compilers had that kind of behaviour.
To be clear. Parentheses have three different purposes.
- Used to enclose an argument list when defining or calling procedure
- To indicate an indexer on an array.
- As an operator in an expression.
There are two ways to call a procedure either as a statement or as an expression.
Expression:-
x = func(y)
Statement:-
func y
Note the Call
keyword invokes the procedure as if it were part of an expression hence the argument list must be contained in parantheses.
In the above that y
itself represents a very simple expession. We could well have used y + z
at this point. In fact we can use any valid expression at this point, including one that uses the parentheses operator. For example:-
x = (y)
is a valid expression. Hence when you do:-
func(y)
VBScript sees the call to func
to which the result of the expression (y)
is passed. Now even if func
defines this parameter as ByRef
the value in y
would be unaffected because y
wasn't actually passed as a parameter. What was passed was the result of the expression (y)
which would be stored somewhere temporary. Even if this temporary store is modified by func
it would be discarded afterwards and hence has the same behaviour had the parameter been marked ByVal
.