Need help with ByRef

Results 1 to 7 of 7

Thread: Need help with ByRef

  1. #1
    Sean Guest

    Default Need help with ByRef

    Can anyone possibly offer any solutions as to why this doesn;t work?<BR><BR>dim myRS<BR>dbCreateRecordset(myRS)<BR>Response.Write "Created...&#060;p&#062;"<BR>dbDestroyRecordset(my RS)<BR>Response.Write "Destroyed...&#060;p&#062;"<BR><BR>sub dbCreateRecordset(ByRef thisObject)<BR> set thisObject = Server.CreateObject("ADODB.Recordset")<BR>end sub<BR><BR>sub dbDestroyRecordset(ByRef thisObject)<BR> thisObject.Close<BR> set thisObject = nothing<BR>end sub<BR><BR><BR>it gives me this output:<BR><BR>Created...<BR><BR><BR>Microsoft VBScript runtime error &#039 800a01a8&#039 <BR><BR>Object required: &#039thisObject&#039 <BR><BR>/test.asp, line 13<BR><BR>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?

  2. #2
    lagerBoy Guest

    Default This isn't the answer

    This doesn&#039t actually answer your question (so why am I posting it? Don&#039t know.)<BR><BR>But I was just reading a good article as your post appeared, if you have time it might be worth a read.<BR><BR><BR><BR>Certainly, I liked the way that they included the error handling.<BR><BR>

  3. #3
    Sean Guest

    Default Heres the solution for anyone who cares....

    sub CreateRS(ByRef thisObject)<BR> set thisObject = Server.CreateObject("ADODB.Recordset")<BR>end sub<BR><BR>sub DestroyRS(ByRef thisObject)<BR> thisObject.Close<BR> set thisObject = nothing<BR>end sub<BR><BR>dim myRS<BR>CreateRS myRS<BR>Response.Write "Created...&#060;p&#062;"<BR>DestroyRD myRS<BR>Response.Write "Destroyed...&#060;p&#062;"<BR><BR>(Note the brackets have been removed from the call to CreateRS?)<BR><BR>also valid is:<BR><BR>call CreateRS(myRS)<BR>Response.Write "Created...&#060;p&#062;"<BR>call DestroyRD(myRS)<BR>Response.Write "Destroyed...&#060;p&#062;"<BR><BR>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 type CreateRS().<BR><BR>Why is this so microsoft? Why isn&#039t there a goddamn standard. pfffffffffffft<BR><BR>anyways, there you go.. and i&#039ve been tearing my hair out over this.... gah

  4. #4
    Join Date
    Dec 1969

    Default WHY the solution works!!!

    I&#039ve alluded to this one before, but never happened to think about it in connection to ByRef! Interesting and informative "catch" you made.<BR><BR>The reason:<BR><BR>The rule still holds; you can NEVER put parentheses around arguments to a Sub *unless* you use the CALL statement.<BR><BR>"Wait a minute!" you object, "I just did it!"<BR><BR>Yes, and many people do it in many other circumstances, such as <BR>&nbsp;&nbsp;&nbsp;&nbsp;Response.Write( "the parens are really a mistake!" )<BR><BR>"So, then, why in the world does it work?"<BR><BR>Let me answer by asking you another question: What constitutes a legal argument in VBScript? Answer: Any expression. Good. <BR><BR>Now, what constitues a legal expression in VBScript (and in most languages)? Answer: Lots of things<BR><BR>variable<BR>constant<BR>variable operator variable<BR>constant operator constant<BR>etc.<BR><BR>If we generalize it, we get:<BR><BR>expression := expression binary-op expression<BR>expression := unary-op expression<BR>expression := ( expression )<BR>expression := variable<BR>expression := constant<BR>and more...<BR><BR>Wait a minute! Did you see the third one there! And expression *CAN BE* an expression enclosed in parentheses! <BR><BR>Why is that needed in the language? To account for expression such as<BR>&nbsp;&nbsp;&nbsp;&nbsp;(5 + 4 ) * 3 <BR>(which give 27, whereas simply 5+4*3 would give 17).<BR><BR>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:<BR>&nbsp;&nbsp;&nbsp;&nbsp;SomeSub (argument1),(argument2)<BR>It&#039s just a lot clearer in such a case as to what is happening.<BR><BR>"Okay," you say, "That&#039s a fine piece of computer language esoterica, but what does that have to do with &#039losing&#039 the ByRef quality of my variable?"<BR><BR>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 <BR>&nbsp;&nbsp;&nbsp;&nbsp;(5 + 4) * 3<BR><BR>And, of course, the process of getting the value from the objRS variable means...The same thing that getting the "value" of any object does with automation: Get the default property of the object. In the case of RecordSet, I *believe* that the default property is the RecordSet.Fields collection. So, when you do<BR>&nbsp;&nbsp;&nbsp;&nbsp;( objRS )<BR>you are really *forcing* (LITERALLY forcing!) VBScript to grab the Fields collection from the RecordSet and pass *THAT* to your "DestroyRD" SUBroutine. And, of course, the DestroyRD subroutine then says "Well, heck, you can&#039t close a Fields collection!" and tosses its cookies on your feet.<BR><BR>To find out for sure if I am right, do this:<BR><BR>&#060;%<BR>sub DestroyRS(ByRef thisObject)<BR>&nbsp;&nbsp;&nbsp;&nbsp;Response.Wr ite TypeName(thisObject) & "&LT;BR&#062;"<BR>&nbsp;&nbsp;&nbsp;&nbsp;thisObje ct.Close<BR>&nbsp;&nbsp;&nbsp;&nbsp;set thisObject = nothing<BR>end sub<BR>...<BR>...<BR>DestroyRD( myRS )<BR>...<BR>%&#062;<BR><BR>And the call to TypeName should print out sufficient info to convince you that you are no longer passing a RecordSet object but are, instead, passing the default property of a RecordSet object.<BR><BR>****************<BR><BR>Now, how is *THAT* for esoterica?<BR><BR>THIS thread should be in the Advanced or Moderated Advanced forum, it is so wondrous and weird a topic and a result!<BR><BR>Bill Wilkinson<BR>

  5. #5
    Join Date
    Dec 1969

    Default Oops! ALMOST correct before...

    ...but here&#039s the straight skinny:<BR><BR>It *is* true that putting parens around an expression forces VBScript to get the *value* of that expression.<BR><BR>But doing<BR>&nbsp;&nbsp;&nbsp;&nbsp;( someRecordSetObject )<BR>does *not* convert the RecordSet to its default property (the Fields collection) as I supposed.<BR><BR>Instead, what happens is that 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&#039s 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<BR>&nbsp;&nbsp;&nbsp;&nbsp;DestroyRS( myRS )<BR><BR>(The object does *NOT* get destroyed, though! Sean&#039s 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.)<BR><BR>HOWEVER...<BR><BR>The real problem is in the <BR>&nbsp;&nbsp;&nbsp;&nbsp;Sub CreateRS( ByRef thisObject )<BR><BR>Now, when you call it from the "mainline" code via<BR>&nbsp;&nbsp;&nbsp;&nbsp;CreateRS( myRS )<BR>*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*!!!<BR><BR>So my original reason was close, but the problem was in the CreateRS call, not the DestroyRS call. <BR><BR>And, in any case, the lesson to be learned here is *NEVER* use parens when calling a SUB, *even* a one-argument sub where it *looks* like you can get away with it.<BR><BR>Heck, even if all you are passing is a simple number, putting the parens around the value cause a completely unneeded copy to be made, so just don&#039t do it!<BR><BR><BR>

  6. #6
    Sean ( Guest

    Default RE: WHY the solution works!!!

    Hi Bill,<BR><BR>thanks for the post. I wouldn&#039t have even known about it unless it was mentioned on the front page of 4guys. <BR><BR>Since discovering that little *issue* i&#039ve stopped using brackets around arguments to subroutines... I do however use brackets when there are no arguments, is printHeader() (It just makes it easier for me to read.. "Ahh yes, subroutine...")<BR><BR>Thanks again.<BR><BR>Sean

  7. #7
    Join Date
    Dec 1969

    Default RE: Slight addition

    This may seem glaringly obviuos to most but I thought it needed to be said.<BR><BR>Whether you use brackets is not determined by if it is a sub or a function but rather whether or not you are assigning the return value. Obviously a sub doesn&#039;t have a return value. If your are assigning the return value then you must use brackets, if you are not then you must NOT use brackets.<BR><BR>eg.<BR><BR>[code language="VBScript"]<BR>function myFunc(byRef x)<BR> x = x + 1<BR> myFunc = true<BR>end function<BR>[/code]<BR><BR>correct usage:<BR><BR>[code language="VBScript"]<BR>myVar = 1<BR><BR>result = myFunc (myVar)<BR>myFunc myVar<BR>response.write myFunc (myVar)<BR>[/code]<BR><BR><BR>The last one may seem slightly confusing since there is no equals sign but you are assigning the return value to the response.write parameter.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts