When you think ASP, think...
Recent Articles xml
All Articles
ASP.NET Articles
Related Web Technologies
User Tips!
Coding Tips
spgif spgif

Sample Chapters
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Stump the SQL Guru!
XML Info
Author an Article
spgif spgif
ASP ASP.NET ASP FAQs Feedback topnav-right
Print this page.
Published: Friday, July 28, 2000

Using Parenthesis in VBScript when Calling a Subroutine

Recently a post on the ASPMessageboard appeared from a stumped developer, named Sean, who was using parenthesis when calling subroutines he had created. Sean's post follows:

- continued -

Need Help with ByRef
Can anyone possibly offer any solutions as to why this doesn't work?

dim myRS
Response.Write "Created...<p>"
Response.Write "Destroyed...<p>"

sub dbCreateRecordset(ByRef thisObject)
set thisObject = Server.CreateObject("ADODB.Recordset")
end sub

sub dbDestroyRecordset(ByRef thisObject)
set thisObject = nothing
end sub

it gives me this output:


Microsoft VBScript runtime error ' 800a01a8' 

Object required: 'thisObject' 

/test.asp, line 13
I thought the ByRef statement was supposed to pass the address of the variable and not the actual value of the variable. It would seem that this is not the case?
[Read Sean's Post]

Shortly after his post, Sean posted a reply stating that he had discovered the problem - not using parenthesis when calling a subroutine that expects a parameter by reference (ByRef). Sean's second post is as follows:

[To fix this I had to remove the parenthesis when calling the subroutine.] I have no idea why.. I can only assume that it is because when you refer to CreateRS(myRS), it tries to lookup the value of myRS and then pass it... ie: myRS is not set to anything, so its like typ[ing] CreateRS().

Why is this so Microsoft? Why isn't there a goddamn standard. pfffffffffffft... Anyways, there you go.. and i've been tearing my hair out over this.... gah!
[Read Sean's Second Post]

Avid ASPMessageboard poster Bill Wilkinson replied to this in two posts, sheding light on why one can use parenthesis when calling a subroutine at certain times (like using Response.Write("Some Text") but not in others (as in Sean's example). The remainder of this article is a synopsis of Bill's posts.

I've alluded to this one before, but never happened to think about it in connection to ByRef! Interesting and informative "catch" you made.

The reason: The rule still holds; you can NEVER put parentheses around arguments to a Sub unless you use the CALL statement.

"Wait a minute!" you object, "I just did it!"

Yes, and many people do it in many other circumstances, such as Response.Write( "the parens are really a mistake!" ). "So, then, why in the world does it work?"

Let me answer by asking you another question: What constitutes a legal argument in VBScript? Answer: Any expression. Good. Now, what constitues a legal expression in VBScript (and in most languages)? Answer: Lots of things

  • variable
  • constant
  • variable operator variable
  • constant operator constant
  • etc.

If we generalize it, we get:

expression := expression binary-op expression
expression := unary-op expression
expression := ( expression )
expression := variable
expression := constant
and more...

Wait a minute! Did you see the third one there! And expression CAN BE an expression enclosed in parentheses! Why is that needed in the language? To account for expression such as (5 + 4 ) * 3 (which give 27, whereas simply 5+4*3 would give 17).

And THAT is what is being accepted by VBScript when you use parens when calling a SUB that takes only one argument! You can do the same thing with two-argument SUBs:

SomeSub (argument1),(argument2)

It's just a lot clearer in such a case as to what is happening.

"Okay," you say, "That's a fine piece of computer language esoterica, but what does that have to do with 'losing' the ByRef quality of my variable?"

The answer: Anytime you wrap an expression in parentheses, VBScript assumes that you need to get its VALUE (because it assumes it will then need the value in order to perform a subsequent calculation, as in the case of (5 + 4) * 3. And, of course, the process of getting the value from the objRS variable means... a *copy* of the reference to the object is created, and that becomes the thing that is then passed to the Sub. Since multiple references to the same object are still indeed referencing the same object, Sean's DestroyRS code would work, since all he does in that code is call a method on the object. And the recordset gets closed, even when you call the method via DestroyRS( myRS ). (The object does NOT get destroyed, though! Sean's code sets the reference received to Nothing, but remember that with the parens all he is receiving in the SUB is a copy of the original reference. So the original reference is still hanging around referencing the RecordSet and so the RecordSet can not be collected by the garbage collection system.)


The real problem is in the Sub CreateRS( ByRef thisObject ). Now, when you call it from the "mainline" code via CreateRS( myRS ) again the contents of the variable myRS are copied by the "expression parentheses" there. Then the Sub assigns the newly created RecordSet to the thus-passed copy. But when the Sub returns, there is nothing to force the value now in the copy BACK into the original variable!!!

To see that I am right, do this:

Sub CreateRS(ByRef thisObject)
	Set thisObject = Server.CreateObject("ADODB.RecordSet")
End Sub

and then, in the mainline code, this:

Dim rs1, rs2
CreateRS rs1
Response.Write "rs1 has VarType=" & VarType(rs1) & " and TypeName=" &
TypeName(rs1) & "<BR>" & vbNewLine
CreateRS( rs2 )
Response.Write "rs2 has VarType=" & VarType(rs2) & " and TypeName=" &
TypeName(rs2) & "<BR>" & vbNewLine

And the results you see will be:

rs1 has VarType=9 and TypeName=Recordset
rs2 has VarType=0 and TypeName=Empty

Which clearly shows the source of the original problem.

Happy Programming!

Read Bill Wilkinson's first post...
Read Bill Wilkinson's second post...

ASP.NET [1.x] [2.0] | ASPFAQs.com | Advertise | Feedback | Author an Article