Need Help with
Can anyone possibly offer any solutions as to why this doesn't work?
dim myRS dbCreateRecordset(myRS) Response.Write "Created...<p>" dbDestroyRecordset(myRS) Response.Write "Destroyed...<p>" sub dbCreateRecordset(ByRef thisObject) set thisObject = Server.CreateObject("ADODB.Recordset") end sub sub dbDestroyRecordset(ByRef thisObject) thisObject.Close set thisObject = nothing end sub
it gives me this output:
I thought theCreated... Microsoft VBScript runtime error ' 800a01a8' Object required: 'thisObject' /test.asp, line 13
ByRefstatement 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
myRSand then pass it... ie:
myRSis not set to anything, so its like typ[ing]
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
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 rule still holds; you can NEVER put parentheses around arguments to a Sub unless you use the
"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 operator variable
- constant operator constant
If we generalize it, we get:
expression := expression binary-op expression
expression := unary-op expression
expression := ( expression )
expression := variable
expression := constant
Wait a minute! Did you see the third one there! And expression CAN BE an expression enclosed in
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:
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
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,
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
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:
and then, in the mainline code, this:
And the results you see will be:
Which clearly shows the source of the original problem.