Fabulous Adventures In Coding

Eric Lippert's Blog

What do you mean "cannot use parentheses?"

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.

Published Monday, September 15, 2003 1:09 PM by Eric Lippert
Filed under: ,

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

 

Deadprogrammer said:

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.
September 16, 2003 6:39 PM
 

Eric Lippert said:

I live to serve!
September 16, 2003 7:24 PM
 

Fabulous Adventures In Coding said:

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.
February 18, 2004 8:54 PM
 

Fabulous Adventures In Coding said:

May 6, 2004 12:44 PM
 

Fabulous Adventures In Coding said:

May 6, 2004 12:50 PM
 

Fabulous Adventures In Coding said:

May 6, 2004 1:05 PM
 

Fabulous Adventures In Coding said:

It occurs to me that there may be some confusion about what exactly
May 6, 2004 1:08 PM
 

Curtis said:

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 !!!!
May 25, 2005 5:35 AM
 

Eric Lippert said:

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.
May 25, 2005 1:51 PM
 

Jan Lourens said:

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.
July 21, 2005 3:50 AM
 

Aaron said:

Thanks Eric, I know for certain I 'learned' this quite some time ago, and you have taught me once again.
August 9, 2005 4:45 PM
 

anon said:

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)
January 9, 2006 6:07 PM
 

Clinton said:

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.
April 18, 2006 4:47 AM
 

Martin said:

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?
June 28, 2006 2:32 PM
 

Eric Lippert said:

Yes, the syntax is the same for VB6/VBA.  The VBScript syntax and semantics were designed for compatibility with VB6.
June 28, 2006 4:21 PM
 

Visakh said:

Hi Eric,

Thanks a lot for the article. This error was bugging me for an hour!!!  I am calling VBS function inside JSTL and i thot it was mixing of scripts which caused the issue. Does this mean, i have to split the 2 behaviors into 2 functions, if i have to call the Sub with 2 parameters?

Regards

Visakh

November 26, 2006 12:27 AM
 

Jan Philipp Giel said:

I am a bit confused right now.

In your newsgroup posting (1) you say

n = Foo((z))       ' legal, passes z by reference

and in your blog it is "to pass x byval"

z = f((x))

I guess "by value" is the right one?

(1) http://www.mvps.org/scripting/languages/eric_lippert_parens_in_procedures.txt

December 11, 2006 5:17 AM
 

Weblog said:

Taken from: http://blogs.msdn.com/ericlippert/archive/2003/09/15/52996.aspx What do you mean &quot;cannot

December 12, 2006 3:47 PM
 

Eric Lippert said:

Jan: yes, the newsgroup posting has a typo. I regret the error.

December 12, 2006 4:07 PM
 

NikitaP said:

Just add "Call " before you function call. Worked for me.

February 12, 2007 2:26 PM
 

Avoiding Negative Alpha » VBScript Recursive List of Files in all Folders and Subfolders V2! said:

April 17, 2007 9:37 AM
 

Avoiding Negative Alpha » Blog Archive » VBScript Recursive List of File Attributes/Properties in all Folders and Subfolders V2! said:

April 25, 2007 9:46 PM
 

vm said:

kind of relevant.. the error could happen if you don't include javascript: tag before a javascript function call on a page having both vbscript and javascript.

May 11, 2007 6:35 PM
 

システム管理な雑記 -- Sleeve notes of a sysadmin -- said:

メモ: サンプル、 PowerShell, etc... (VBScript)

June 1, 2007 3:10 PM
 

システム管理な雑記 -- Sleeve notes of a sysadmin -- said:

メモ: サンプル、 PowerShell, etc... (VBScript)

June 1, 2007 3:20 PM
 

k0nvikt said:

Can you then tell me how do you call a sub when an error occurs in vbs

Tried :"On Error mySub()" did'nt work

June 13, 2007 4:55 AM
 

Eric Lippert said:

VBScript only supports "On Error Resume Next" for error handling, sorry.

June 13, 2007 12:23 PM
 

DrewGuy said:

Hey, I just wanted to thank you. I'm incredibly new to VB of any kind, and your site provided the answer after a couple hours of struggling with this problem. You rock!

August 21, 2007 1:21 PM
 

san said:

why am i getting this error while trying to set a response.status and response.addheader

September 14, 2007 12:42 PM
 

VBScript nitpicking (the good kind) - Part 2 said:

October 2, 2007 11:55 PM
 

Beez said:

This is evil.  I wonder if this is a Basic artifact?  I hated this and just spent an afternoon trying to figure out why my subroutine's change to the value of it's parameter did not persist when the subroutine returned *cry*

October 4, 2007 6:06 PM
 

?????????? ??-VBScript - ?????? 2 said:

October 7, 2007 2:37 PM
 

Famous Quotes » Fabulous Adventures In Coding : More On ByRef vs ByVal said:

January 4, 2008 9:18 PM
 

dKes said:

Hi Eric,

I get the error message above. Here is a part of script - what is wrong?

Set objShell = WScript.CreateObject("WScript.Shell")

objShell.Run ("ftp -s:" & chr(34) & strFTPScriptFileName & chr(34), , True)

dKes

February 12, 2008 5:16 PM
 

JAaronAnderson.com said:

the examples of "to pass x byref, y byref: " and others do not make sense to me? Please help me understand...

thx

March 3, 2008 2:12 PM
 

Eric Lippert said:

I wrote an article about that a mere six hours after I wrote the article above! :-)

http://blogs.msdn.com/ericlippert/archive/2003/09/15/53005.aspx

March 3, 2008 2:17 PM
 

VBScript Nitpicking (the good kind) - part.2 | AdvancedQTP said:

March 30, 2008 1:59 PM
 

SD said:

Great explanation.  Thank you!!!

May 14, 2008 1:58 PM
 

Fehler Nr.13 | hilpers said:

January 20, 2009 11:06 AM
 

response.writeLine | keyongtech said:

January 21, 2009 10:38 PM
 

Evaluation d'expression arithm?tiques | hilpers said:

January 22, 2009 9:20 AM
 

Randy said:

Eric,

Great post.

I have the following in a file show.vbs:

Sub Show()

  MsgBox "Show"

End Sub

call Show()

call Show

Show()

Show

All of these invocations seem to work.  I would have thought that two of these would be incorrect.  Or is there something I'm missing with the no arguments scenario?  e.g. in VBA if you were to try Show() it would tell you that "Expected: =" which makes sense under 3.1 -- VBA sees the parentheses and assumes that the call should be a Function so there should be an assignment.

Thanks.

January 28, 2009 9:45 PM
 

Al Dunbar said:

show(a) does not error out, however it may not do exactly as you'd expect for the reasons given long ago by Eric. Anyway, I'm not surprised that none of the four examples above errors out, as I see the issue mainly showing up when the number of arguments is greater than one.

May 7, 2009 8:42 PM
 

I talk to VBscript said:

I read your explaination once and didnt understand it.

i tried it out and nothing worked.

I read it again and swore at the screen severl times and still nothing worked.

I read it again and tried it again and swore a lot more and then started talking to my reflection in the screen and things started to work.

I owe you beer for the good of my mental health.

June 11, 2009 3:11 AM
 

all said:

how to write this?

Set WshShell = WScript.CreateObject("WScript.Shell")

WshShell.Run(iexplore -k http://support.microsoft.com/kb/154780, 1, true)

November 30, 2009 9:51 PM

Leave a Comment

(required) 
(optional)
(required) 

  
Enter Code Here: Required
Submit

About Eric Lippert

Eric Lippert is a senior developer on the Microsoft C# compiler team. Before that he worked on the framework of Visual Studio Tools For Office. Before that, he worked on the compilers, runtimes and tools for VBScript, JScript, Windows Script Host and other Microsoft Scripting technologies. He lives in Seattle and spends his free time editing books about programming languages, playing the piano, and trying to keep his tiny sailboat upright in Puget Sound.

This Blog

Syndication


© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker