Home All Groups Group Topic Archive Search About
Author
21 Jun 2009 8:33 PM
David
If a string is declared locally at the termination of the procedure string
memory should be recovered.

=====================
However, when does the compiler recover memory for a string used in an
object declaration:

    Set rsTemp = DaoDb.OpenRecordset("MyTBLName")

or in a parameter for a called procedure?

    Call MyProcedure("MyTBLName")

--------------------

Logic says:

1)  For object declaration it would be after execution of the statement -- 
Set rsTemp

2) For the Called procedure it would also be after the called procedure is
executed.

OR

would both strings be considered local to the procedure in which they reside
and not be cleared until that procedures stack is popped?

----------------------

Also, is there any advantage to clearing a string in a local procedure that
is used early in the procedure and not used again?

Author
22 Jun 2009 1:10 AM
Jim Mack
David wrote:

> If a string is declared locally at the termination of the procedure
> string memory should be recovered.

It is.


> =====================
> However, when does the compiler recover memory for a string used in
> an object declaration:
>
>     Set rsTemp = DaoDb.OpenRecordset("MyTBLName")
>
> or in a parameter for a called procedure?
>
>     Call MyProcedure("MyTBLName")

Immediate (literal) strings used as parameters are discarded on return
from the call. They're temporaries. They'll always occupy some memory,
though -- the contents have to come from somewhere.


> --------------------
>
> Logic says:
>
> 1)  For object declaration it would be after execution of the
> statement -- Set rsTemp
>
> 2) For the Called procedure it would also be after the called
> procedure is executed.

Yes to both.


> OR
>
> would both strings be considered local to the procedure in which
> they reside and not be cleared until that procedures stack is
> popped?

That would be true for declared locals strings, but not for immediate
strings.


> ----------------------
>
> Also, is there any advantage to clearing a string in a local
> procedure that is used early in the procedure and not used again?

Not unless it's huge.

--
   Jim Mack
   Twisted tees at http://www.cafepress.com/2050inc
   "We sew confusion"
Author
22 Jun 2009 1:12 AM
Bill McCarthy
Hi David,

With OpenRecordset the name is passed in ByRef. It's unfortunate but due to
the way OLE Strings work, if the argument was ByVal it would mean the value
would need to be copied.  That is the strings are not immutable, so passing
ByVal requires the value to be copied. ByRef means that a pointer to the
variable is passed in. The ByRef with OLE Strings negates the overhead of
copying at the expense of encapsulation: you don't know if the method being
called actually modifies the string.

Your code :

>    Set rsTemp = DaoDb.OpenRecordset("MyTBLName")

Is the equivalent of :

Dim var As String
var = "MyTBLName"
Set rsTemp = DaoDb.OpenRecordset(var)

In that calling block the lifetime of the string is the lifetime of var,
minus anything OpenRecordset might do. For example, OpenRecordset could set
the variable to nothing, eg:

Sub OpenRecordset(ByRef name As String)
   ' some code here
   name = vbNullString
End sub

If the code was like that, and you called upon it:

Dim var As String
var = "MyTBLName"
Set rsTemp = DaoDb.OpenRecordset(var)
MsgBox var

You'd get an empty message box because the string has been pointed to a new
string.

So the lifetime is generally the calling block, but because the arguments
are passed ByRef, the code being called can change the lifetime.









Show quoteHide quote
"David" <dw85745***@earthlink.net> wrote in message
news:uCWWI%23q8JHA.4976@TK2MSFTNGP04.phx.gbl...
> If a string is declared locally at the termination of the procedure string
> memory should be recovered.
>
> =====================
> However, when does the compiler recover memory for a string used in an
> object declaration:
>
>    Set rsTemp = DaoDb.OpenRecordset("MyTBLName")
>
> or in a parameter for a called procedure?
>
>    Call MyProcedure("MyTBLName")
>
> --------------------
>
> Logic says:
>
> 1)  For object declaration it would be after execution of the statement -- 
> Set rsTemp
>
> 2) For the Called procedure it would also be after the called procedure is
> executed.
>
> OR
>
> would both strings be considered local to the procedure in which they
> reside and not be cleared until that procedures stack is popped?
>
> ----------------------
>
> Also, is there any advantage to clearing a string in a local procedure
> that is used early in the procedure and not used again?
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
Author
22 Jun 2009 12:26 PM
David
Mr. Mack and Mr. McCarthy:

Both of you seem to be in agreement except for the use of the literal string
passed as a parameter (Mr. Mack refers to it as an intermediate) vs. local
variable declaration and assignment.  Mr. McCarthy indicates the following
are equivalent.

================
Your code :

>    Set rsTemp = DaoDb.OpenRecordset("MyTBLName")

Is the equivalent of :

Dim var As String
var = "MyTBLName"
Set rsTemp = DaoDb.OpenRecordset(var)

====================

However, per Mr. Mack, they would not be equivalent as "var" would be
retained to the end of the calling procedure, while the string "literal"
parameter would  be destroyed after the call.

So who is right?




Show quoteHide quote
"Bill McCarthy" <TPASoft.com Are Identity Thieves> wrote in message
news:eTV9Dgt8JHA.200@TK2MSFTNGP05.phx.gbl...
> Hi David,
>
> With OpenRecordset the name is passed in ByRef. It's unfortunate but due
> to the way OLE Strings work, if the argument was ByVal it would mean the
> value would need to be copied.  That is the strings are not immutable, so
> passing ByVal requires the value to be copied. ByRef means that a pointer
> to the variable is passed in. The ByRef with OLE Strings negates the
> overhead of copying at the expense of encapsulation: you don't know if the
> method being called actually modifies the string.
>
> Your code :
>
>>    Set rsTemp = DaoDb.OpenRecordset("MyTBLName")
>
> Is the equivalent of :
>
> Dim var As String
> var = "MyTBLName"
> Set rsTemp = DaoDb.OpenRecordset(var)
>
> In that calling block the lifetime of the string is the lifetime of var,
> minus anything OpenRecordset might do. For example, OpenRecordset could
> set the variable to nothing, eg:
>
> Sub OpenRecordset(ByRef name As String)
>   ' some code here
>   name = vbNullString
> End sub
>
> If the code was like that, and you called upon it:
>
> Dim var As String
> var = "MyTBLName"
> Set rsTemp = DaoDb.OpenRecordset(var)
> MsgBox var
>
> You'd get an empty message box because the string has been pointed to a
> new string.
>
> So the lifetime is generally the calling block, but because the arguments
> are passed ByRef, the code being called can change the lifetime.
>
>
>
>
>
>
>
>
>
> "David" <dw85745***@earthlink.net> wrote in message
> news:uCWWI%23q8JHA.4976@TK2MSFTNGP04.phx.gbl...
>> If a string is declared locally at the termination of the procedure
>> string memory should be recovered.
>>
>> =====================
>> However, when does the compiler recover memory for a string used in an
>> object declaration:
>>
>>    Set rsTemp = DaoDb.OpenRecordset("MyTBLName")
>>
>> or in a parameter for a called procedure?
>>
>>    Call MyProcedure("MyTBLName")
>>
>> --------------------
>>
>> Logic says:
>>
>> 1)  For object declaration it would be after execution of the
>> statement --  Set rsTemp
>>
>> 2) For the Called procedure it would also be after the called procedure
>> is executed.
>>
>> OR
>>
>> would both strings be considered local to the procedure in which they
>> reside and not be cleared until that procedures stack is popped?
>>
>> ----------------------
>>
>> Also, is there any advantage to clearing a string in a local procedure
>> that is used early in the procedure and not used again?
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>
Author
22 Jun 2009 12:39 PM
Ralph
Show quote Hide quote
"David" <dw85745***@earthlink.net> wrote in message
news:unXIgSz8JHA.4976@TK2MSFTNGP04.phx.gbl...
> Mr. Mack and Mr. McCarthy:
>
> Both of you seem to be in agreement except for the use of the literal
string
> passed as a parameter (Mr. Mack refers to it as an intermediate) vs. local
> variable declaration and assignment.  Mr. McCarthy indicates the following
> are equivalent.
>
> ================
> Your code :
>
> >    Set rsTemp = DaoDb.OpenRecordset("MyTBLName")
>
> Is the equivalent of :
>
> Dim var As String
> var = "MyTBLName"
> Set rsTemp = DaoDb.OpenRecordset(var)
>
> ====================
>
> However, per Mr. Mack, they would not be equivalent as "var" would be
> retained to the end of the calling procedure, while the string "literal"
> parameter would  be destroyed after the call.
>
> So who is right?
>

Neither
Author
22 Jun 2009 12:51 PM
Jim Mack
David wrote:
> Mr. Mack and Mr. McCarthy:
>
> Both of you seem to be in agreement except for the use of the
> literal string passed as a parameter (Mr. Mack refers to it as an
> intermediate) vs. local variable declaration and assignment.  Mr.
> McCarthy indicates the following are equivalent.

FWIW I called it an 'immediate', not an 'intermediate'. Just another
way of saying 'literal'.

Show quoteHide quote
> ================
> Your code :
>
>>    Set rsTemp = DaoDb.OpenRecordset("MyTBLName")
>
> Is the equivalent of :
>
> Dim var As String
> var = "MyTBLName"
> Set rsTemp = DaoDb.OpenRecordset(var)
>
> ====================
>
> However, per Mr. Mack, they would not be equivalent as "var" would
> be retained to the end of the calling procedure, while the string
> "literal" parameter would  be destroyed after the call.
>
> So who is right?

Functionally, we both are.

What McCarthy shows is the logical equivalent, not necessarily the
physical equivalent. The missing step is an implied "var =
vbNullString" following the call.

There must be a BSTR temporary created to pass into the function, and
its contents must come from somewhere.  The 'somewhere' in this case
is the program memory occupied by the literal. That memory, the
literal string, never goes away while your program is running.

But the BSTR created for the call is released as soon as the function
returns. There's still a 4-byte descriptor on the stack, just as if
you had said 'Dim var As String', but it's a null pointer.

So the string descriptor lives on the stack and will go away as part
of leaving the local function, but the contents it pointed to are gone
by that point. Except, of course, for the literal, which has program
scope and life -- nothing you can do about that.

--
   Jim Mack
   Twisted tees at http://www.cafepress.com/2050inc
   "We sew confusion"
Author
22 Jun 2009 12:57 PM
Bill McCarthy
Hi David,

Are you asking whether or not :

Sub Foo
    Set rsTemp = DaoDb.OpenRecordset("MyTBLName")
  '(a) released here
   ' more code
   '(b) released here
End Sub

?  If so I make no claim as to either.  It'd be hard to test other than
looking at the registers as this is the kind of thing an optimizing compiler
should be able to decide on.  The string literal is initialized as an OLE
String probably using SysAllocStringLen. Inside Foo a call to SysFreeString
will also be made on that variable. Whether or not that variable still
points to the same string depends on the code  in the method being called.;
it is however unlikely OpenRecordset would modify the string, but in other
code it is something to be wary of.
Whether SysFreeString is called at (a) or (b), I'm not sure.  It's rare that
would matter. If it did, you could ensure it is by coding it as:

Dim var As String
var = "MyTBLName"
Set rsTemp = DaoDb.OpenRecordset(var)
var = vbNullString






Show quoteHide quote
"David" <dw85745***@earthlink.net> wrote in message
news:unXIgSz8JHA.4976@TK2MSFTNGP04.phx.gbl...
> Mr. Mack and Mr. McCarthy:
>
> Both of you seem to be in agreement except for the use of the literal
> string passed as a parameter (Mr. Mack refers to it as an intermediate)
> vs. local variable declaration and assignment.  Mr. McCarthy indicates the
> following are equivalent.
>
> ================
> Your code :
>
>>    Set rsTemp = DaoDb.OpenRecordset("MyTBLName")
>
> Is the equivalent of :
>
> Dim var As String
> var = "MyTBLName"
> Set rsTemp = DaoDb.OpenRecordset(var)
>
> ====================
>
> However, per Mr. Mack, they would not be equivalent as "var" would be
> retained to the end of the calling procedure, while the string "literal"
> parameter would  be destroyed after the call.
>
> So who is right?
>
>
>
>
> "Bill McCarthy" <TPASoft.com Are Identity Thieves> wrote in message
> news:eTV9Dgt8JHA.200@TK2MSFTNGP05.phx.gbl...
>> Hi David,
>>
>> With OpenRecordset the name is passed in ByRef. It's unfortunate but due
>> to the way OLE Strings work, if the argument was ByVal it would mean the
>> value would need to be copied.  That is the strings are not immutable, so
>> passing ByVal requires the value to be copied. ByRef means that a pointer
>> to the variable is passed in. The ByRef with OLE Strings negates the
>> overhead of copying at the expense of encapsulation: you don't know if
>> the method being called actually modifies the string.
>>
>> Your code :
>>
>>>    Set rsTemp = DaoDb.OpenRecordset("MyTBLName")
>>
>> Is the equivalent of :
>>
>> Dim var As String
>> var = "MyTBLName"
>> Set rsTemp = DaoDb.OpenRecordset(var)
>>
>> In that calling block the lifetime of the string is the lifetime of var,
>> minus anything OpenRecordset might do. For example, OpenRecordset could
>> set the variable to nothing, eg:
>>
>> Sub OpenRecordset(ByRef name As String)
>>   ' some code here
>>   name = vbNullString
>> End sub
>>
>> If the code was like that, and you called upon it:
>>
>> Dim var As String
>> var = "MyTBLName"
>> Set rsTemp = DaoDb.OpenRecordset(var)
>> MsgBox var
>>
>> You'd get an empty message box because the string has been pointed to a
>> new string.
>>
>> So the lifetime is generally the calling block, but because the arguments
>> are passed ByRef, the code being called can change the lifetime.
>>
>>
>>
>>
>>
>>
>>
>>
>>
>> "David" <dw85745***@earthlink.net> wrote in message
>> news:uCWWI%23q8JHA.4976@TK2MSFTNGP04.phx.gbl...
>>> If a string is declared locally at the termination of the procedure
>>> string memory should be recovered.
>>>
>>> =====================
>>> However, when does the compiler recover memory for a string used in an
>>> object declaration:
>>>
>>>    Set rsTemp = DaoDb.OpenRecordset("MyTBLName")
>>>
>>> or in a parameter for a called procedure?
>>>
>>>    Call MyProcedure("MyTBLName")
>>>
>>> --------------------
>>>
>>> Logic says:
>>>
>>> 1)  For object declaration it would be after execution of the
>>> statement --  Set rsTemp
>>>
>>> 2) For the Called procedure it would also be after the called procedure
>>> is executed.
>>>
>>> OR
>>>
>>> would both strings be considered local to the procedure in which they
>>> reside and not be cleared until that procedures stack is popped?
>>>
>>> ----------------------
>>>
>>> Also, is there any advantage to clearing a string in a local procedure
>>> that is used early in the procedure and not used again?
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>
>
>
Author
22 Jun 2009 3:23 PM
mayayana
>
> Both of you seem to be in agreement except for the use of the literal
string
> passed as a parameter .....
> However, per Mr. Mack, they would not be equivalent as "var" would be
> retained to the end of the calling procedure, while the string "literal"
> parameter would  be destroyed after the call.
>
> So who is right?
>

  What difference does it make? Are you planning
to pass 2 MB literal strings?

   It's interesting how the most nitpicking technical
questions never fail to elicit the most interest. :)

    While I defer to Jim Mack and Ralph in terms of
expertise with this, I think there's also another aspect
to your angels-on-the-head-of-a-pin count: Matthew
Curland, in his VB book, demonstrates the inefficiency
of repeated string concatenation. In the course of
that discussion he points out that there's a 64 KB
"string cache" that "essentially guarantees that you
can't mess up too badly with small strings, no
matter how bad the code is." Which is to say that
even if it mattered whether you reclaimed the memory
from your 20-odd byte string, it still really doesn't.
Author
22 Jun 2009 9:27 PM
Wolfgang Enzinger
On Mon, 22 Jun 2009 11:12:05 +1000, "Bill McCarthy" <TPASoft.com Are
Identity Thieves> wrote:

>With OpenRecordset the name is passed in ByRef.

I doubt that.

Here is the IDL definition for the OpenRecordset method (DAO 3.6):

         [id(0x60030027), helpcontext(0x0010110b)]
         HRESULT OpenRecordset(
                         [in] BSTR Name,
                         [in, optional] VARIANT Type,
                         [in, optional] VARIANT Options,
                         [in, optional] VARIANT LockEdit,
                         [out, retval] Recordset** pprst);

IMHO that says clearly that the Name parameter is passed ByVal. If it
was passed ByRef, it would look like this:

                         [in, out] BSTR* Name

If I'm wrong, just let me know. If not, just do likewise, without
another 20+ posts party. *g*
Author
23 Jun 2009 2:32 AM
Bill McCarthy
"Wolfgang Enzinger" <usenet200***@temporaryforwarding.com> wrote in message
news:8msv35t4t8i2f98hpu0vuemrkiqrn4tott@4ax.com...
> On Mon, 22 Jun 2009 11:12:05 +1000, "Bill McCarthy" <TPASoft.com Are
> Identity Thieves> wrote:
>
>>With OpenRecordset the name is passed in ByRef.
>
> I doubt that.
>

Strange, here it shows in object browser as if ByRef. It would make more
sense for it to be ByVal. Perhaps this is a limitation of the VB Object
browser and external libraries. It does show the ByVal for one's own code.



Show quoteHide quote
> Here is the IDL definition for the OpenRecordset method (DAO 3.6):
>
>         [id(0x60030027), helpcontext(0x0010110b)]
>         HRESULT OpenRecordset(
>                         [in] BSTR Name,
>                         [in, optional] VARIANT Type,
>                         [in, optional] VARIANT Options,
>                         [in, optional] VARIANT LockEdit,
>                         [out, retval] Recordset** pprst);
>
> IMHO that says clearly that the Name parameter is passed ByVal. If it
> was passed ByRef, it would look like this:
>
>                         [in, out] BSTR* Name
>
> If I'm wrong, just let me know. If not, just do likewise, without
> another 20+ posts party. *g*
Author
22 Jun 2009 12:38 PM
Ralph
Show quote Hide quote
"David" <dw85745***@earthlink.net> wrote in message
news:uCWWI%23q8JHA.4976@TK2MSFTNGP04.phx.gbl...
> If a string is declared locally at the termination of the procedure string
> memory should be recovered.
>
> =====================
> However, when does the compiler recover memory for a string used in an
> object declaration:
>
>     Set rsTemp = DaoDb.OpenRecordset("MyTBLName")
>
> or in a parameter for a called procedure?
>
>     Call MyProcedure("MyTBLName")
>
> --------------------
>
> Logic says:
>
> 1)  For object declaration it would be after execution of the statement --
> Set rsTemp
>
> 2) For the Called procedure it would also be after the called procedure is
> executed.
>
> OR
>
> would both strings be considered local to the procedure in which they
reside
> and not be cleared until that procedures stack is popped?
>
> ----------------------
>
> Also, is there any advantage to clearing a string in a local procedure
that
> is used early in the procedure and not used again?
>

ha, Well here is my two cents ...

In the examples given , using VB*, no "string memory" would ever be
'cleared' or 'recovered', as no "string-memory" would ever be created.
Because you are using literal string constants. These strings are stored in
the string section of the programs data segment.

During development the name or identifier for these strings is the string
itself and it evaluates to an address in the Data section. So in all your
examples, you would be passing the address of a 'hard-coded' block of
memory.

Each of the procedures would be using only the Data section address for
these strings.

Also note that OLE marshalling is not involved as it appears you are using
DAO for your object example. DAO runs inproc.

hth
-ralph

[VB* this assumes you are using the classic VB COM-based development
platform(VB6 or lower)]
Author
22 Jun 2009 12:57 PM
Bill McCarthy
Hi Ralph,

but surely the code being called is expecting an OLE BSTR ByRef. and as such
could change the string reference. What does VB6 do there ?  Let's say the
code being called is :

Sub Bar(ByRef x as String)
  x = "baz"
  ' more code
End Sub

Wouldn't VB have to call SysFreeStr when the new value is assigned to x ??







Show quoteHide quote
"Ralph" <nt_consultin***@yahoo.com> wrote in message
news:%23OMI8az8JHA.3544@TK2MSFTNGP04.phx.gbl...
>
> "David" <dw85745***@earthlink.net> wrote in message
> news:uCWWI%23q8JHA.4976@TK2MSFTNGP04.phx.gbl...
>> If a string is declared locally at the termination of the procedure
>> string
>> memory should be recovered.
>>
>> =====================
>> However, when does the compiler recover memory for a string used in an
>> object declaration:
>>
>>     Set rsTemp = DaoDb.OpenRecordset("MyTBLName")
>>
>> or in a parameter for a called procedure?
>>
>>     Call MyProcedure("MyTBLName")
>>
>> --------------------
>>
>> Logic says:
>>
>> 1)  For object declaration it would be after execution of the
>> statement --
>> Set rsTemp
>>
>> 2) For the Called procedure it would also be after the called procedure
>> is
>> executed.
>>
>> OR
>>
>> would both strings be considered local to the procedure in which they
> reside
>> and not be cleared until that procedures stack is popped?
>>
>> ----------------------
>>
>> Also, is there any advantage to clearing a string in a local procedure
> that
>> is used early in the procedure and not used again?
>>
>
> ha, Well here is my two cents ...
>
> In the examples given , using VB*, no "string memory" would ever be
> 'cleared' or 'recovered', as no "string-memory" would ever be created.
> Because you are using literal string constants. These strings are stored
> in
> the string section of the programs data segment.
>
> During development the name or identifier for these strings is the string
> itself and it evaluates to an address in the Data section. So in all your
> examples, you would be passing the address of a 'hard-coded' block of
> memory.
>
> Each of the procedures would be using only the Data section address for
> these strings.
>
> Also note that OLE marshalling is not involved as it appears you are using
> DAO for your object example. DAO runs inproc.
>
> hth
> -ralph
>
> [VB* this assumes you are using the classic VB COM-based development
> platform(VB6 or lower)]
>
>
Author
22 Jun 2009 2:03 PM
Ralph
Show quote Hide quote
"Bill McCarthy" <TPASoft.com Are Identity Thieves> wrote in message
news:uVt39jz8JHA.4976@TK2MSFTNGP04.phx.gbl...
> Hi Ralph,
>
> but surely the code being called is expecting an OLE BSTR ByRef. and as
such
> could change the string reference. What does VB6 do there ?  Let's say the
> code being called is :
>
> Sub Bar(ByRef x as String)
>   x = "baz"
>   ' more code
> End Sub
>
> Wouldn't VB have to call SysFreeStr when the new value is assigned to x ??
>

No.

This is a point of common confusion with the classic VB development
platform. We often say it is "COM-based", and it is. It's objects (Classes,
Forms, and Controls) follow COM protocol. It's datatypes are suspiciously
OLE datatypes (not really that strange when you consider VB support was
behind the design, if not the original emphasis, of OLE. But, COM is only a
specification. It's implementation (well MS's implementation) is by OLE. OLE
itself is both a specification and an implementation.

Thus VB's inherent and created objects behave and act identical (or rather
damn close) to ActiveX objects. Most analogies fit. That's the beauty of a
common object model. But the internal implementation is very different.

Unfortunately the VB Runtime is proprietorial and essentially hidden. We can
make good guesses as to what it's doing, but hard proof is hard to come by.

In your example, within VB, "x" is merely an auto variable on the stack
containing a pointer to a block of memory in the Data string section.

-ralph
Author
22 Jun 2009 2:16 PM
Bill McCarthy
hi Ralph,

> In your example, within VB, "x" is merely an auto variable on the stack
> containing a pointer to a block of memory in the Data string section.
>

I don't think so.  Take my example

>> Sub Bar(ByRef x as String)
>>   x = "baz"
>>   ' more code
>> End Sub

inside the method Bar, there is no way for the compiler to know if a literal
is passed in or not.  As it is a reference to a string. SysFreeString *must*
be called to release the string.    I think if you also check VarPtr, StrPtr
or call Len on the string you will see it not only is, but must be an OLE
BSTR. Also, if it was just a pointer to the string table, then Mid(x,1) =
"a" etc, would modify the string table
My guess is VB loads it's string table, but creates OLE strings and copies
the data into them.


Show quoteHide quote
"Ralph" <nt_consultin***@yahoo.com> wrote in message
news:%23gC2MK08JHA.3916@TK2MSFTNGP02.phx.gbl...
>
> "Bill McCarthy" <TPASoft.com Are Identity Thieves> wrote in message
> news:uVt39jz8JHA.4976@TK2MSFTNGP04.phx.gbl...
>> Hi Ralph,
>>
>> but surely the code being called is expecting an OLE BSTR ByRef. and as
> such
>> could change the string reference. What does VB6 do there ?  Let's say
>> the
>> code being called is :
>>
>> Sub Bar(ByRef x as String)
>>   x = "baz"
>>   ' more code
>> End Sub
>>
>> Wouldn't VB have to call SysFreeStr when the new value is assigned to x
>> ??
>>
>
> No.
>
> This is a point of common confusion with the classic VB development
> platform. We often say it is "COM-based", and it is. It's objects
> (Classes,
> Forms, and Controls) follow COM protocol. It's datatypes are suspiciously
> OLE datatypes (not really that strange when you consider VB support was
> behind the design, if not the original emphasis, of OLE. But, COM is only
> a
> specification. It's implementation (well MS's implementation) is by OLE.
> OLE
> itself is both a specification and an implementation.
>
> Thus VB's inherent and created objects behave and act identical (or rather
> damn close) to ActiveX objects. Most analogies fit. That's the beauty of a
> common object model. But the internal implementation is very different.
>
> Unfortunately the VB Runtime is proprietorial and essentially hidden. We
> can
> make good guesses as to what it's doing, but hard proof is hard to come
> by.
>
> In your example, within VB, "x" is merely an auto variable on the stack
> containing a pointer to a block of memory in the Data string section.
>
> -ralph
>
>
>
Author
22 Jun 2009 3:07 PM
Ralph
Show quote Hide quote
"Bill McCarthy" <TPASoft.com Are Identity Thieves> wrote in message
news:efdlkR08JHA.2604@TK2MSFTNGP05.phx.gbl...
> hi Ralph,
>
> > In your example, within VB, "x" is merely an auto variable on the stack
> > containing a pointer to a block of memory in the Data string section.
> >
>
> I don't think so.  Take my example
>
> >> Sub Bar(ByRef x as String)
> >>   x = "baz"
> >>   ' more code
> >> End Sub
>
> inside the method Bar, there is no way for the compiler to know if a
literal
> is passed in or not.  As it is a reference to a string. SysFreeString
*must*
> be called to release the string.    I think if you also check VarPtr,
StrPtr
> or call Len on the string you will see it not only is, but must be an OLE
> BSTR. Also, if it was just a pointer to the string table, then Mid(x,1) =
> "a" etc, would modify the string table
> My guess is VB loads it's string table, but creates OLE strings and copies
> the data into them.
>

Sorry, but that's not how it works for internal objects, and your guess is
essentially wrong on a global scale, with the proviso that the Data string
section is read-only, ie, r-value only, no l-value, and in VB - Strings are
objects. So yes, whenever you "touch" them you often get a "thing". Why?
Because you asked for one. Duh.

And again don't be so surprised to discover VB Strings are OLE Bstrs. Where
do you think "OLE Bstrs" came from?

-ralph
Author
22 Jun 2009 3:45 PM
Bill McCarthy
Hi Ralph,

Show quoteHide quote
"Ralph" <nt_consultin***@yahoo.com> wrote in message
news:uMVp4t08JHA.1340@TK2MSFTNGP05.phx.gbl...
>
> "Bill McCarthy" <TPASoft.com Are Identity Thieves> wrote in message
> news:efdlkR08JHA.2604@TK2MSFTNGP05.phx.gbl...
>> hi Ralph,
>>
>> > In your example, within VB, "x" is merely an auto variable on the stack
>> > containing a pointer to a block of memory in the Data string section.
>> >
>>
>> I don't think so.  Take my example
>>
>> >> Sub Bar(ByRef x as String)
>> >>   x = "baz"
>> >>   ' more code
>> >> End Sub
>>
>> inside the method Bar, there is no way for the compiler to know if a
> literal
>> is passed in or not.  As it is a reference to a string. SysFreeString
> *must*
>> be called to release the string.    I think if you also check VarPtr,
> StrPtr
>> or call Len on the string you will see it not only is, but must be an OLE
>> BSTR. Also, if it was just a pointer to the string table, then Mid(x,1) =
>> "a" etc, would modify the string table
>> My guess is VB loads it's string table, but creates OLE strings and
>> copies
>> the data into them.
>>
>
> Sorry, but that's not how it works for internal objects, and your guess is
> essentially wrong on a global scale, with the proviso that the Data string
> section is read-only, ie, r-value only, no l-value,

You've got me lost there.  r-value only and l-value is a compile time thing.
Obviously string tables you'd want read only, but there is no magic
protection that silently swallows any attempts to write there.  Code that
re-assigns the ByRef variable or modifies the string, or calls Len, StrPtr,
VarPtr etc, cannot be on a pointer to the string table treated as r-values
only.


> and in VB - Strings are
> objects. So yes, whenever you "touch" them you often get a "thing". Why?
> Because you asked for one. Duh.
>


They are "touched" by being defined as a parameter beign passed into a
function.


> And again don't be so surprised to discover VB Strings are OLE Bstrs.
> Where
> do you think "OLE Bstrs" came from?
>

I don't get what you are referring to here.  I said they are OLE BSTR's,
been saying that for over a decade now so it's no surprise to me.  I think
you are badly mistaken if you think OLE BSTRs are not passed to methods that
declare there parameters as such.  The only thing I can think of is perhaps
you are confusing the use of string literals in VB's own internal string
manipulation inside a method, such as if you wrote "abc" & "def".  But
passed as a parameter the contract must be met, and that means using an OLE
string, and that by definition precludes a pointer direct to the string
constant's table.
Author
22 Jun 2009 2:03 PM
David
I'm a little over my  head here hence my question.

But from my simplistic assessment logic says:

1)  The literal in each procedure in included in the string table and
remains their (in the table) throughout program execution.
2)  During compilation a pointer is assigned to get to each string
in the order in which it is needed
3)  Whether the string is used as a calling parameter
or assigned and/or reassigned in the local procedure, the pointers to the
string are pushed on the stack and not removed until the procedure ends when
the stack is cleared (popped).

To do otherwise seems very inefficient as:
1)  the pointer takes up little space, and
2)  to go down through the stack to find it (the pointer), remove it, and
then recreate the stack seems a lot of work



Show quoteHide quote
"Bill McCarthy" <TPASoft.com Are Identity Thieves> wrote in message
news:uVt39jz8JHA.4976@TK2MSFTNGP04.phx.gbl...
> Hi Ralph,
>
> but surely the code being called is expecting an OLE BSTR ByRef. and as
> such could change the string reference. What does VB6 do there ?  Let's
> say the code being called is :
>
> Sub Bar(ByRef x as String)
>  x = "baz"
>  ' more code
> End Sub
>
> Wouldn't VB have to call SysFreeStr when the new value is assigned to x ??
>
>
>
>
>
>
>
> "Ralph" <nt_consultin***@yahoo.com> wrote in message
> news:%23OMI8az8JHA.3544@TK2MSFTNGP04.phx.gbl...
>>
>> "David" <dw85745***@earthlink.net> wrote in message
>> news:uCWWI%23q8JHA.4976@TK2MSFTNGP04.phx.gbl...
>>> If a string is declared locally at the termination of the procedure
>>> string
>>> memory should be recovered.
>>>
>>> =====================
>>> However, when does the compiler recover memory for a string used in an
>>> object declaration:
>>>
>>>     Set rsTemp = DaoDb.OpenRecordset("MyTBLName")
>>>
>>> or in a parameter for a called procedure?
>>>
>>>     Call MyProcedure("MyTBLName")
>>>
>>> --------------------
>>>
>>> Logic says:
>>>
>>> 1)  For object declaration it would be after execution of the
>>> statement --
>>> Set rsTemp
>>>
>>> 2) For the Called procedure it would also be after the called procedure
>>> is
>>> executed.
>>>
>>> OR
>>>
>>> would both strings be considered local to the procedure in which they
>> reside
>>> and not be cleared until that procedures stack is popped?
>>>
>>> ----------------------
>>>
>>> Also, is there any advantage to clearing a string in a local procedure
>> that
>>> is used early in the procedure and not used again?
>>>
>>
>> ha, Well here is my two cents ...
>>
>> In the examples given , using VB*, no "string memory" would ever be
>> 'cleared' or 'recovered', as no "string-memory" would ever be created.
>> Because you are using literal string constants. These strings are stored
>> in
>> the string section of the programs data segment.
>>
>> During development the name or identifier for these strings is the string
>> itself and it evaluates to an address in the Data section. So in all your
>> examples, you would be passing the address of a 'hard-coded' block of
>> memory.
>>
>> Each of the procedures would be using only the Data section address for
>> these strings.
>>
>> Also note that OLE marshalling is not involved as it appears you are
>> using
>> DAO for your object example. DAO runs inproc.
>>
>> hth
>> -ralph
>>
>> [VB* this assumes you are using the classic VB COM-based development
>> platform(VB6 or lower)]
>>
>>
>
Author
22 Jun 2009 2:26 PM
Bill McCarthy
Hi David,

The method being called, especially if it is an external library written in
possibly a different language, expects an OLE BSTR ByRef.  That must have
the in memory structure of an OLE BSTR which means it contains a value that
points to the start of the string, and the four bytes prior to that indicate
the length of the string.  VB may load it's string tables as such, but there
are still other issues. Consider this code :

Sub Foo(ByRef x As String)
  MsgBox x
  Mid(x, 1, 1) = "a"
End Sub

If you called that such as :

Foo "zzz"

The second time you called that, it should display "azz" if in fact a
pointer to the string table was passed in. Remember the code being called
upon, Foo in this case, can't know before hand whether a literal or a
variable is passed into it.



Show quoteHide quote
"David" <dw85745***@earthlink.net> wrote in message
news:O3coHJ08JHA.3544@TK2MSFTNGP04.phx.gbl...
> I'm a little over my  head here hence my question.
>
> But from my simplistic assessment logic says:
>
> 1)  The literal in each procedure in included in the string table and
> remains their (in the table) throughout program execution.
> 2)  During compilation a pointer is assigned to get to each string
> in the order in which it is needed
> 3)  Whether the string is used as a calling parameter
> or assigned and/or reassigned in the local procedure, the pointers to the
> string are pushed on the stack and not removed until the procedure ends
> when the stack is cleared (popped).
>
> To do otherwise seems very inefficient as:
> 1)  the pointer takes up little space, and
> 2)  to go down through the stack to find it (the pointer), remove it, and
> then recreate the stack seems a lot of work
>
>
>
> "Bill McCarthy" <TPASoft.com Are Identity Thieves> wrote in message
> news:uVt39jz8JHA.4976@TK2MSFTNGP04.phx.gbl...
>> Hi Ralph,
>>
>> but surely the code being called is expecting an OLE BSTR ByRef. and as
>> such could change the string reference. What does VB6 do there ?  Let's
>> say the code being called is :
>>
>> Sub Bar(ByRef x as String)
>>  x = "baz"
>>  ' more code
>> End Sub
>>
>> Wouldn't VB have to call SysFreeStr when the new value is assigned to x
>> ??
>>
>>
>>
>>
>>
>>
>>
>> "Ralph" <nt_consultin***@yahoo.com> wrote in message
>> news:%23OMI8az8JHA.3544@TK2MSFTNGP04.phx.gbl...
>>>
>>> "David" <dw85745***@earthlink.net> wrote in message
>>> news:uCWWI%23q8JHA.4976@TK2MSFTNGP04.phx.gbl...
>>>> If a string is declared locally at the termination of the procedure
>>>> string
>>>> memory should be recovered.
>>>>
>>>> =====================
>>>> However, when does the compiler recover memory for a string used in an
>>>> object declaration:
>>>>
>>>>     Set rsTemp = DaoDb.OpenRecordset("MyTBLName")
>>>>
>>>> or in a parameter for a called procedure?
>>>>
>>>>     Call MyProcedure("MyTBLName")
>>>>
>>>> --------------------
>>>>
>>>> Logic says:
>>>>
>>>> 1)  For object declaration it would be after execution of the
>>>> statement --
>>>> Set rsTemp
>>>>
>>>> 2) For the Called procedure it would also be after the called procedure
>>>> is
>>>> executed.
>>>>
>>>> OR
>>>>
>>>> would both strings be considered local to the procedure in which they
>>> reside
>>>> and not be cleared until that procedures stack is popped?
>>>>
>>>> ----------------------
>>>>
>>>> Also, is there any advantage to clearing a string in a local procedure
>>> that
>>>> is used early in the procedure and not used again?
>>>>
>>>
>>> ha, Well here is my two cents ...
>>>
>>> In the examples given , using VB*, no "string memory" would ever be
>>> 'cleared' or 'recovered', as no "string-memory" would ever be created.
>>> Because you are using literal string constants. These strings are stored
>>> in
>>> the string section of the programs data segment.
>>>
>>> During development the name or identifier for these strings is the
>>> string
>>> itself and it evaluates to an address in the Data section. So in all
>>> your
>>> examples, you would be passing the address of a 'hard-coded' block of
>>> memory.
>>>
>>> Each of the procedures would be using only the Data section address for
>>> these strings.
>>>
>>> Also note that OLE marshalling is not involved as it appears you are
>>> using
>>> DAO for your object example. DAO runs inproc.
>>>
>>> hth
>>> -ralph
>>>
>>> [VB* this assumes you are using the classic VB COM-based development
>>> platform(VB6 or lower)]
>>>
>>>
>>
>
>
Author
22 Jun 2009 3:09 PM
Ralph
Show quote Hide quote
"Bill McCarthy" <TPASoft.com Are Identity Thieves> wrote in message
news:uqei4V08JHA.5704@TK2MSFTNGP03.phx.gbl...
> Hi David,
>
> The method being called, especially if it is an external library written
in
> possibly a different language, expects an OLE BSTR ByRef.  That must have
> the in memory structure of an OLE BSTR which means it contains a value
that
> points to the start of the string, and the four bytes prior to that
indicate
> the length of the string.  VB may load it's string tables as such, but
there
> are still other issues. Consider this code :
>
> Sub Foo(ByRef x As String)
>   MsgBox x
>   Mid(x, 1, 1) = "a"
> End Sub
>
> If you called that such as :
>
> Foo "zzz"
>
> The second time you called that, it should display "azz" if in fact a
> pointer to the string table was passed in. Remember the code being called
> upon, Foo in this case, can't know before hand whether a literal or a
> variable is passed into it.
>

If the OP had asked about calling an ActiveX component, then your comments
might have some relevancy, but he didn't and they aren't.

-ralph
Author
22 Jun 2009 3:28 PM
Bill McCarthy
Hi Ralph,

Show quoteHide quote
"Ralph" <nt_consultin***@yahoo.com> wrote in message
news:O2km$u08JHA.5064@TK2MSFTNGP03.phx.gbl...
>
> "Bill McCarthy" <TPASoft.com Are Identity Thieves> wrote in message
> news:uqei4V08JHA.5704@TK2MSFTNGP03.phx.gbl...
>> Hi David,
>>
>> The method being called, especially if it is an external library written
> in
>> possibly a different language, expects an OLE BSTR ByRef.  That must have
>> the in memory structure of an OLE BSTR which means it contains a value
> that
>> points to the start of the string, and the four bytes prior to that
> indicate
>> the length of the string.  VB may load it's string tables as such, but
> there
>> are still other issues. Consider this code :
>>
>> Sub Foo(ByRef x As String)
>>   MsgBox x
>>   Mid(x, 1, 1) = "a"
>> End Sub
>>
>> If you called that such as :
>>
>> Foo "zzz"
>>
>> The second time you called that, it should display "azz" if in fact a
>> pointer to the string table was passed in. Remember the code being called
>> upon, Foo in this case, can't know before hand whether a literal or a
>> variable is passed into it.
>>
>
> If the OP had asked about calling an ActiveX component, then your comments
> might have some relevancy, but he didn't and they aren't.
>

I think the DAO code he showed was in fact an external library, but the case
is the same with internal methods.  If you have the method Foo as above, and
call it with a literal and also with a variable, the compiler cannot
optimize that out, it has to respect the OLE BSTR contract.
Author
22 Jun 2009 2:39 PM
Ralph
Show quote Hide quote
"David" <dw85745***@earthlink.net> wrote in message
news:O3coHJ08JHA.3544@TK2MSFTNGP04.phx.gbl...
> I'm a little over my  head here hence my question.
>
> But from my simplistic assessment logic says:
>
> 1)  The literal in each procedure in included in the string table and
> remains their (in the table) throughout program execution.
> 2)  During compilation a pointer is assigned to get to each string
> in the order in which it is needed
> 3)  Whether the string is used as a calling parameter
> or assigned and/or reassigned in the local procedure, the pointers to the
> string are pushed on the stack and not removed until the procedure ends
when
> the stack is cleared (popped).
>
> To do otherwise seems very inefficient as:
> 1)  the pointer takes up little space, and
> 2)  to go down through the stack to find it (the pointer), remove it, and
> then recreate the stack seems a lot of work
>

Basically correct except for this statement:
"During compilation a pointer is assigned to get to each string in the order
in which it is needed"

Note: there are two different environments one needs to consider when taking
about 'classic' VB.
1) There is the design-time VBIDE where all code is parsed and converted to
pcode during development. [Note: And this is particularly important (not so
much in this context, but useful to keep in mind whenever you delve into VB
"internals" <smile>, ie, likely to come up later), the 'text' you see
displayed in the VBEditor is purely an artifact. Consider it as the parser's
way of providing an interactive interface to the programmer.]

So at design-time whenever a literal string constant is used it is place in
an internal cache/table and the literal string is replaced in pcode with a
lookup into that table. (It appears to be a combined token, something like
<table>.<offset>.) How many of these tables and where they are located
depends on 'scope'. Const values are stored in their own tables, again by
"scope".

In actual use temp vars may or may not be created depending on context.

2) At compile-time, whether pcode or native, these string tables are bundled
up and placed in a Data string section. And the lookups are replace with an
address into that data section.
Note: When compiling native code with string optimization on, this section
is further analyzed for duplicates. Duplicates are removed and all locations
that use the same string receive the same address.

On occasion within a procedure the VB parser seems to do a bit of string
optimization itself.

The eventual order in the Data String section probably corresponds with the
order they appeared in the translating units as they compile, but I wouldn't
count on it.

-ralph
Author
22 Jun 2009 2:37 PM
Jim Mack
Ralph wrote:
Show quoteHide quote
>
> ha, Well here is my two cents ...
>
> In the examples given , using VB*, no "string memory" would ever be
> 'cleared' or 'recovered', as no "string-memory" would ever be
> created. Because you are using literal string constants. These
> strings are stored in the string section of the programs data
> segment.
>
> During development the name or identifier for these strings is the
> string itself and it evaluates to an address in the Data section.
> So in all your examples, you would be passing the address of a
> 'hard-coded' block of memory.
>
> Each of the procedures would be using only the Data section address
> for these strings.

In an ideal world, yes. But not in VB-land.

As a writer of DLLs called by VB, both TLB-based and Declared, I've
been on both ends of such calls. In every case, VB creates a temporary
BSTR, passes it to the function, and destroys it on return. The
external function cannot know whether the contents of the BSTR came
from a static string, a computed string, a literal, or whatever. In
every case it sees a BSTR (in the case of Declared functions, an Ansi
BSTR which is one step removed from the original).

What you describe is possible, given a contract that calls for it, but
in VB no such contract is ever negotiated. Even in cases where the
external function expects a LPSZ, VB will pass a BSTR that mimics one.
Every time.

--
   Jim Mack
   Twisted tees at http://www.cafepress.com/2050inc
   "We sew confusion"
Author
22 Jun 2009 3:12 PM
Ralph
Show quote Hide quote
"Jim Mack" <jmack@mdxi.nospam.com> wrote in message
news:%23nvTpb08JHA.2120@TK2MSFTNGP02.phx.gbl...
> Ralph wrote:
> >
> > ha, Well here is my two cents ...
> >
> > In the examples given , using VB*, no "string memory" would ever be
> > 'cleared' or 'recovered', as no "string-memory" would ever be
> > created. Because you are using literal string constants. These
> > strings are stored in the string section of the programs data
> > segment.
> >
> > During development the name or identifier for these strings is the
> > string itself and it evaluates to an address in the Data section.
> > So in all your examples, you would be passing the address of a
> > 'hard-coded' block of memory.
> >
> > Each of the procedures would be using only the Data section address
> > for these strings.
>
> In an ideal world, yes. But not in VB-land.
>
> As a writer of DLLs called by VB, both TLB-based and Declared, I've
> been on both ends of such calls. In every case, VB creates a temporary
> BSTR, passes it to the function, and destroys it on return. The
> external function cannot know whether the contents of the BSTR came
> from a static string, a computed string, a literal, or whatever. In
> every case it sees a BSTR (in the case of Declared functions, an Ansi
> BSTR which is one step removed from the original).
>
> What you describe is possible, given a contract that calls for it, but
> in VB no such contract is ever negotiated. Even in cases where the
> external function expects a LPSZ, VB will pass a BSTR that mimics one.
> Every time.
>

If the OP had asked about calling an external regular dll, then your
comments would have some relevancy, but he didn't and they aren't.

-ralph
Author
22 Jun 2009 4:23 PM
Jim Mack
Ralph wrote:
>
> If the OP had asked about calling an external regular dll, then your
> comments would have some relevancy, but he didn't and they aren't.

Which of these OP scenarios are you referring to?

   Set rsTemp = DaoDb.OpenRecordset("MyTBLName")

   Call MyProcedure("MyTBLName")

The first clearly makes reference to something external and will
follow the path I set out.

I haven't examined the compiler output for the second, so I can't
speak about with direct experience. The best you can say is that it
depends on the prototype for MyProcedure. If it's expecting a Variant,
for example, or a String by reference, then VB has no choice but to
create a BSTR using the contents of the literal.

If it's expecting a String by value, then it will still create a BSTR
because for internal procedures, "ByVal As String" has a different
meaning than it does for external procedures. Internally, VB will
create a copy of the string to protect its value.

So in each case you can infer that a BSTR will be created and passed.

--
        Jim
Author
22 Jun 2009 5:44 PM
Ralph
Show quote Hide quote
"Jim Mack" <jmack@mdxi.nospam.com> wrote in message
news:OoOvVX18JHA.5704@TK2MSFTNGP03.phx.gbl...
> Ralph wrote:
> >
> > If the OP had asked about calling an external regular dll, then your
> > comments would have some relevancy, but he didn't and they aren't.
>
> Which of these OP scenarios are you referring to?
>
>    Set rsTemp = DaoDb.OpenRecordset("MyTBLName")
>
>    Call MyProcedure("MyTBLName")
>
> The first clearly makes reference to something external and will
> follow the path I set out.
>

There is no evidence that "DaoDb" is an external object. It could be a VB
Class. If it is in fact a DAO access library object, then their is little
difference, since the object is created in the application space just as
though it was a VB Class. (Don't confuse DAO with ADO - they are to very
different implementations, though share a similar interface.)

> I haven't examined the compiler output for the second, so I can't
> speak about with direct experience. The best you can say is that it
> depends on the prototype for MyProcedure. If it's expecting a Variant,
> for example, or a String by reference, then VB has no choice but to
> create a BSTR using the contents of the literal.
>
> If it's expecting a String by value, then it will still create a BSTR
> because for internal procedures, "ByVal As String" has a different
> meaning than it does for external procedures. Internally, VB will
> create a copy of the string to protect its value.
>
> So in each case you can infer that a BSTR will be created and passed.
>

Not necessarily. The OP used literal string constants in his examples. They
are not objects - they are simply pointers to a Data string section. The
OP's question was when is this "string memory" recovered? The simple answer
is never - it was never allocated in the first place.

You are correct that generally you can "infer" that eventually the called
procedure may construct an object and thus allocate memory for its
construction, but then maybe not. Depends on what one asks VB to do. But in
any case the called procedure takes on all responsibility. There was no
"string memory" going in, and hopefully there will be no lingering "string
memory" when it returns. lol

-ralph
Author
22 Jun 2009 6:04 PM
Jim Mack
Ralph wrote:
Show quoteHide quote
> Jim Mack wrote...
>>
>> Which of these OP scenarios are you referring to?
>>
>>    Set rsTemp = DaoDb.OpenRecordset("MyTBLName")
>>
>>    Call MyProcedure("MyTBLName")
>>
>> The first clearly makes reference to something external and will
>> follow the path I set out.
>
> There is no evidence that "DaoDb" is an external object. It could
> be a VB Class. If it is in fact a DAO access library object, then
> their is little difference, since the object is created in the
> application space just as though it was a VB Class. (Don't confuse
> DAO with ADO - they are to very different implementations, though
> share a similar interface.)

No matter what it is, you have to examine this from the perspective of
the called procedure and what contract it has with VB.

The called proc must be able to accept strings from VB, no matter
where they come from. They could be temporaries, variant-contained,
locals, literals, globals, whatever. So there must be a consistent,
contracted way of passing these in.

Unless you're saying that the called proc can change its behavior and
its interface when called with a literal string as an argument, I
think you have to agree that what arrives at the callee is the same in
all cases. And that must be a BSTR if anything input could be a BSTR
(and we know it can).

>>  ...
>>
>> So in each case you can infer that a BSTR will be created and
>> passed.
>>
>
> Not necessarily. The OP used literal string constants in his
> examples. They are not objects - they are simply pointers to a Data
> string section. The OP's question was when is this "string memory"
> recovered? The simple answer is never - it was never allocated in
> the first place.

Here I can only repeat the above. If the callee CAN accept a BSTR,
then it MUST be passed one, by contract. I would love to hear how the
callee, which is opaque to the caller, can alter its behavior to
accept a simple pointer when it expects a BSTR.

> ...  But in any case the called procedure takes on all
> responsibility.

Including publishing an interface that the caller must honor.

> There was no "string memory" going in, and
> hopefully there will be no lingering "string memory" when it
> returns. lol

I completely disagree, and I have yet to hear the basis for this
claim. Yes, the data can be traced back to a stringtable. But a
stringtable does not contain BSTR, which is what must be passed to an
arbitrary callee. It must be copied to one for passing.

Gawd, this sounds like a discussion in a C group. (-:

--
        Jim
Author
22 Jun 2009 6:34 PM
Ralph
Show quote Hide quote
"Jim Mack" <jmack@mdxi.nospam.com> wrote in message
news:%23M2qzP28JHA.3916@TK2MSFTNGP02.phx.gbl...

>
> Here I can only repeat the above. If the callee CAN accept a BSTR,
> then it MUST be passed one, by contract. I would love to hear how the
> callee, which is opaque to the caller, can alter its behavior to
> accept a simple pointer when it expects a BSTR.
>
> > ...  But in any case the called procedure takes on all
> > responsibility.
>
> Including publishing an interface that the caller must honor.
>
> > There was no "string memory" going in, and
> > hopefully there will be no lingering "string memory" when it
> > returns. lol
>
> I completely disagree, and I have yet to hear the basis for this
> claim. Yes, the data can be traced back to a stringtable. But a
> stringtable does not contain BSTR, which is what must be passed to an
> arbitrary callee. It must be copied to one for passing.
>
> Gawd, this sounds like a discussion in a C group. (-:

It does. And it would likely take a decent grounding in C/Coff/... to
understand what is going on. As far a 'basis' goes, you can simply compile a
few apps and look. You would discover that VB can be quite variable
conditionally on how it handles "strings" (an object, an lpstr, a bstr).

I like your use of the term "by contract". In practical use that is probably
as good way to view the situation as any. Since when it gets right down to
it, it doesn't matter what is really going on - you will get the behavior
you expect.

-ralph
Author
25 Jun 2009 10:53 AM
Bill McCarthy
Hi David,

I decided to run a couple of simple tests on this. Having two methods,
Foo1(ByVal x as String), and Foo2(ByRef x as string). In both of those
methods I just set a form field value to the len(x).  So timing calling
these methods in large loops, the larger the string being passed in, the
larger the difference between ByRef and ByVal.  This is because ByVal
requires a new BSTR to be created.
As these were large loops in the order of millions, it's pretty safe to
assume that VB released the created strings immediately. In the first test
case I used local variable, later I moved that variable up to a form field
level to ensure the compiler could not safely optimize it out.  The results
were the same and showed the ByVal call taking significantly longer. As the
compiler could not know the value of that variable on each iteration, it has
to create a new string, but as the memory didn't significantly grow it's
safe to say it was releasing them on each iteration. Whether or not this
applies outside of loops can only be speculated but one would presume the
compiler would do the same thing.

Next I ran the tests with a Const string and also with a string literal.
There was no difference between the Const variable and literal string in
terms of results to each other, but compared to a string variable, they were
significantly slower with the ByRef calls.  In fact, the ByRef and ByVal
calls came in much of a muchness. This makes sense, as the ByRef calls would
also require the creation of a new BSTR.
so if you had a loop, this :

Dim s as String
s = "...some large string ........."
For i = 0 to count
  Foo2 s
Next i

Would be faster than either:

Const s = "...some large string ........."
For i = 0 to count
  Foo2 s
Next i

or

For i = 0 to count
  Foo2 "...some large string ........."
Next i


This tells us that indeed a new string is being created for the literals and
for Const strings as well.





Show quoteHide quote
"David" <dw85745***@earthlink.net> wrote in message
news:uCWWI%23q8JHA.4976@TK2MSFTNGP04.phx.gbl...
> If a string is declared locally at the termination of the procedure string
> memory should be recovered.
>
> =====================
> However, when does the compiler recover memory for a string used in an
> object declaration:
>
>    Set rsTemp = DaoDb.OpenRecordset("MyTBLName")
>
> or in a parameter for a called procedure?
>
>    Call MyProcedure("MyTBLName")
>
> --------------------
>
> Logic says:
>
> 1)  For object declaration it would be after execution of the statement -- 
> Set rsTemp
>
> 2) For the Called procedure it would also be after the called procedure is
> executed.
>
> OR
>
> would both strings be considered local to the procedure in which they
> reside and not be cleared until that procedures stack is popped?
>
> ----------------------
>
> Also, is there any advantage to clearing a string in a local procedure
> that is used early in the procedure and not used again?
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
Author
25 Jun 2009 3:37 PM
Ralph
Show quote Hide quote
"Bill McCarthy" <TPASoft.com Are Identity Thieves> wrote in message
news:eoQjVNY9JHA.1336@TK2MSFTNGP05.phx.gbl...
> Hi David,
>
> I decided to run a couple of simple tests on this. Having two methods,
> Foo1(ByVal x as String), and Foo2(ByRef x as string). In both of those
> methods I just set a form field value to the len(x).  So timing calling
> these methods in large loops, the larger the string being passed in, the
> larger the difference between ByRef and ByVal.  This is because ByVal
> requires a new BSTR to be created.
> As these were large loops in the order of millions, it's pretty safe to
> assume that VB released the created strings immediately. In the first test
> case I used local variable, later I moved that variable up to a form field
> level to ensure the compiler could not safely optimize it out.  The
results
> were the same and showed the ByVal call taking significantly longer. As
the
> compiler could not know the value of that variable on each iteration, it
has
> to create a new string, but as the memory didn't significantly grow it's
> safe to say it was releasing them on each iteration. Whether or not this
> applies outside of loops can only be speculated but one would presume the
> compiler would do the same thing.
>
> Next I ran the tests with a Const string and also with a string literal.
> There was no difference between the Const variable and literal string in
> terms of results to each other, but compared to a string variable, they
were
> significantly slower with the ByRef calls.  In fact, the ByRef and ByVal
> calls came in much of a muchness. This makes sense, as the ByRef calls
would
> also require the creation of a new BSTR.
> so if you had a loop, this :
>
> Dim s as String
> s = "...some large string ........."
> For i = 0 to count
>   Foo2 s
> Next i
>
> Would be faster than either:
>
> Const s = "...some large string ........."
> For i = 0 to count
>   Foo2 s
> Next i
>
> or
>
> For i = 0 to count
>   Foo2 "...some large string ........."
> Next i
>
>
> This tells us that indeed a new string is being created for the literals
and
> for Const strings as well.
>

Congratuations, you have provided conclusive and uncontroversial proof that
if one Declares a String variable in VB, VB provides one!

[The crowd cheers! It is pandemonium in the Hall!]
Author
26 Jun 2009 1:52 AM
Bill McCarthy
Hi Ralph,

Show quoteHide quote
"Ralph" <nt_consultin***@yahoo.com> wrote in message
news:e3mCLta9JHA.1336@TK2MSFTNGP05.phx.gbl...
>
> "Bill McCarthy" <TPASoft.com Are Identity Thieves> wrote in message
> news:eoQjVNY9JHA.1336@TK2MSFTNGP05.phx.gbl...
>> Hi David,
>>
>> I decided to run a couple of simple tests on this. Having two methods,
>> Foo1(ByVal x as String), and Foo2(ByRef x as string). In both of those
>> methods I just set a form field value to the len(x).  So timing calling
>> these methods in large loops, the larger the string being passed in, the
>> larger the difference between ByRef and ByVal.  This is because ByVal
>> requires a new BSTR to be created.
>> As these were large loops in the order of millions, it's pretty safe to
>> assume that VB released the created strings immediately. In the first
>> test
>> case I used local variable, later I moved that variable up to a form
>> field
>> level to ensure the compiler could not safely optimize it out.  The
> results
>> were the same and showed the ByVal call taking significantly longer. As
> the
>> compiler could not know the value of that variable on each iteration, it
> has
>> to create a new string, but as the memory didn't significantly grow it's
>> safe to say it was releasing them on each iteration. Whether or not this
>> applies outside of loops can only be speculated but one would presume the
>> compiler would do the same thing.
>>
>> Next I ran the tests with a Const string and also with a string literal.
>> There was no difference between the Const variable and literal string in
>> terms of results to each other, but compared to a string variable, they
> were
>> significantly slower with the ByRef calls.  In fact, the ByRef and ByVal
>> calls came in much of a muchness. This makes sense, as the ByRef calls
> would
>> also require the creation of a new BSTR.
>> so if you had a loop, this :
>>
>> Dim s as String
>> s = "...some large string ........."
>> For i = 0 to count
>>   Foo2 s
>> Next i
>>
>> Would be faster than either:
>>
>> Const s = "...some large string ........."
>> For i = 0 to count
>>   Foo2 s
>> Next i
>>
>> or
>>
>> For i = 0 to count
>>   Foo2 "...some large string ........."
>> Next i
>>
>>
>> This tells us that indeed a new string is being created for the literals
> and
>> for Const strings as well.
>>
>
> Congratuations, you have provided conclusive and uncontroversial proof
> that
> if one Declares a String variable in VB, VB provides one!
>
> [The crowd cheers! It is pandemonium in the Hall!]
>

And it conclusively proves your statements about pointers to the string
table were wrong. I guess that accounts for the sarcasm in your post
Author
26 Jun 2009 6:44 AM
Mike Williams
"Bill McCarthy" <Bill McCarthy Is A Liar and A Thief> wrote in message
news:OIr6TJg9JHA.4168@TK2MSFTNGP05.phx.gbl...

> some typical McCarthy rubbish

Why are you still infesting the VB6 group McCarthy? And why do you almost
never post in the VB.Net group? Are your MVP handlers still banning you from
posting there?

Mike