Summary: Why the “Cannot use parentheses when calling a Sub” error occurs in RhinoScript.
Every now and then, I get the error message “Cannot use parentheses when calling a Sub” when calling a function or method. But it does not happen all of the time. For example, the following code appears to work:
Result = MyFunc(MyArg) MySub(MyArg)
But, this code does not work:
Result = MyOtherFunc(MyArg1, MyArg2) MyOtherSub(MyArg1, MyArg2)
In VBScript, parentheses mean several different things:
1) Evaluate a subexpression before the rest of the expression.
Average = (First + Last) / 2)
2) Dereference the index of an array.
Item = MyArray(Index)
3) Call a function or subroutine.
Limit = UBound(MyArray)
4) Pass an argument which would normally be ByRef as ByVal.
' Arg1 is passed ByRef, Arg2 is passed ByVal. Result = MyFunction(Arg1, (Arg2))
And, there are additional rules that apply to item 3:
3.1) An argument list for a function call with an assignment to the returned value must be surrounded by parentheses.
Result = MyFunc(MyArg)
3.2.) An argument list for a subroutine call, or a function call with no assignment, that uses the Call keyword must be surrounded by parentheses.
3.3) If 3.1 and 3.2 do not apply, then the list must not be surrounded by parentheses.
Finally, there is the ByRef rule: arguments are passed ByRef when possible. But, if there are extra parentheses around a variable. then the variable is passed ByVal, not ByRef.
From these rules, it should be clear why the statement MySub(MyArg) is legal but MyOtherSub(MyArg1, MyArg2) is not. The first case appears to be a subroutine call with parentheses around the argument list, but that would violate rule 3.3. Then why does this work? In fact, it is a subroutine call with no parentheses around the argument list, but parentheses around the first argument. This passes the argument by value. The second case is a clear violation of rule 3.3, and there is no way to make it legal, so an error is given.
Here are some examples to what is legal and what is not in VBScript. Suppose X and Y are variables, Func1 is a one argument procedure, and Func2 is a two argument procedure.
To pass X ByRef and Y ByRef:
Func1 X Call Func1(X) Z = Func1(X) Func2 X, Y Call Func2(X, Y) Z = Func2(X, Y)
To pass X ByVal and Y ByRef:
Func1(X) Call Func1((X)) Z = Func1((X)) Func2 (X), Y Func2 ((X)), Y Call Func2((X), Y) Z = Func2((X), Y)
The following will give syntax errors:
Call Func1 X Z = Func1 X Func2(X, Y) Call Func2 X, Y Z = Func2 X, Y