What do you mean "cannot use parentheses?"

What do you mean "cannot use parentheses?"

Rate This
  • Comments 56

Every now and then someone will ask me what the VBScript error message "Cannot use parentheses when calling a Sub" means. I always smile when I hear that question. I tell people that the error means that you CANNOT use PARENTHESES when CALLING a SUB -- which word didn't you understand?

Of course, there is a reason why people ask, even though the error message is perfectly straightforward. Usually what happens is someone writes code like this:

Result = MyFunc(MyArg)
MySub(MyArg)

and it works just fine, so they then write MyOtherSub(MyArg1, MyArg2) only to get the above error.

Here's the deal: parentheses mean several different things in VB and hence in VBScript. They mean:

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: Result = MyFunction(Arg1, (Arg2)) ' Arg1 is passed byref, arg2 is passed byval

That's confusing enough already. Unfortunately, VB and hence VBScript has some weird rules about when #3 applies. The rules are

3.1) An argument list for a function call with an assignment to the returned value must be surrounded by parens: 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 parens: Call MySub(MyArg)
3.3) If 3.1 and 3.2 do not apply then the list must NOT be surrounded by parens.

And finally there is the byref rule: arguments are passed byref when possible but if there are “extra” parens around a variable then the variable is passed byval, not byref.

Now 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 parens around the argument list, but that would violate rule 3.3. Then why is it legal? In fact it is a subroutine call with no parens around the arg list, but parens 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 we give an error.

These rules are confusing and silly, as the designers of Visual Basic .NET realized. VB.NET does away with this rule, and insists that all function and subroutine calls be surrounded by parens. This means that in VB.NET, the statement MySub(MyArg) has different semantics than it does in VBScript and VB6 -- this will pass MyArg byref in VB.NET, byval in VBScript/VB6. This was one of those cases where strict backwards compatibility and usability were in conflict, and usability won.

Here's a handy reference guide to what's legal and what isn't in VBScript: Suppose x and y are vars, f is a one-arg procedure and g is a two-arg procedure.

to pass x byref, y byref:
f x
call f(x)
z = f(x)
g x, y
call g(x, y)
z = g(x, y)

to pass x byval, y byref:
f(x)
call f((x))
z = f((x))
g (x), y
g ((x)), y
call g((x), y)
z = g((x), y)

The following are syntax errors:
call f x
z = f x
g(x, y)
call g x, y
z = g x, y

Ah, VBScript. It just wouldn't be the same without these quirky gotchas.

  • For some time I had a printout from your 1999 usenet post about this taped to my wall. Now it occupies a place of honor in my snippet database. Thank you so much for it.
  • I live to serve!
  • I was talking about reference types vs. by-reference variables a while back. Recall that both JScript and VBScript have reference types (ie, objects) but JScript does not have by-reference variables. COM supports passing variable references around, but unfortunately the intersection of early-bound COM and late-bound IDispatch is a little bit goofy.
  • It occurs to me that there may be some confusion about what exactly
  • DUDE ! YOU Fn ROCK !
    This document is more informative than the MSDN library on this subject.
    I was banging my head against the wall with this same problem for hours. I had 2 arguments and was calling a sub from an onClick and was getting the error At lines 511-513. 8 pages with the same code.

    OK, I have one more Addition to your List of things that will cause the error.

    after I fixed all 8 pages with this... they all started working, no errors. HOWEVER, the main page (default.asp) that DID previously work, was now giving the same error. I could not finger out the problem, hacked out code chunk by chunk... I mean... I ALREADY fixed it... there must be something else I missed.

    after about 20 minutes I realized that the only difference on the main page was that at the very top in the <BODY> tag I was doing an onLoad="subLoadDefaults()" none of the other pages had that.

    WITH the fixed code, that now triggered the errors way down in lines 511- 513....
    now, the funny part is, that before when I had the code WRONG in those same lines, they worked quite fine and no errors. Somehow the onLoad="subLoadDefaults()" made the rest of the page ignore that it was wrong.

    I got rid of the onLoad all together and the page works fine now.

    THANKS !!!!
  • Dude! As I said earlier, I live to serve!

    I'm not sure why your onload guy was causing a problem -- I'd have to actually see the server code in action to figure it out. But I'm glad you've managed to sort out your problem.
  • Eric, you are a friggin' legend! I can't thank you enough for clearing that up for me - been looking like a fool in front of new collueges for hours until I stumbled upon this site.

    Thanks.
  • Thanks Eric, I know for certain I 'learned' this quite some time ago, and you have taught me once again.
  • Another stupid thing that will trigger this error: using

    DateDiff("n", Date1, Date2)

    by itself (not with Response.Write or assigning it to a variable)
  • I can not beleive that it was that simple yet I had stewed over this for ages!  Mate the lights just went on and a big thank you to you.
  • That is the greatest piece of knowledge about sub/function parameters.

    Just one question: Does this byref/byval parens apply as well in VB6 and VBA in which you can actually declared subs and functions by using the byref and byval keywords for parameters?  If it applies, does it overrides default behavior and/or coded behavior?
  • Yes, the syntax is the same for VB6/VBA.  The VBScript syntax and semantics were designed for compatibility with VB6.
Page 1 of 4 (56 items) 1234