Fog Creek Software
Discussion Board




Garbage Collection in VB6

This might be a little off topic for this forum but I have just written my project code to parse a text file (40kb file).

The code getrs parsed into a little heirarchy of classes:
STYLE has many TYPEs
TYPE has many INPUTCONTROLs
              many VARIABLEs
              many FILTERs
VARIABLE has many FILTERs

The main body of my program has one style, it calls that style and initialises it with a text file (style parses the text file).

    Dim fso As FileSystemObject
    Dim fil As File
    Dim fileName As String
    Dim tS As TextStream
   
    fileName = "C:\Documents and Settings\Cassie Harley\Desktop\Reference Project\Harvard.rfm"
    Set fso = CreateObject("Scripting.FileSystemObject")
    Set fil = fso.GetFile(fileName)
    Set tS = fil.OpenAsTextStream(ForReading)
   
    Set tStyle = New Style
    tStyle.after_Initialise (tS.ReadAll)
   
    tS.Close



Will the 'ts.close' close all the child classes?
Or are they just left clogging up the memory?

I ask because it seems that the more I run the program, (run debug run debug...) the slower my computer gets.

Any advice?

Again sorry if this is off topic, please delete it if you think so.

Aussie Chick
Thursday, December 04, 2003

Set all the objects to nothing when you are finished with them.

Damian
Thursday, December 04, 2003

Also before you set them to nothing
use any close / clear / end / quit, etc. method to allow it to free up it's own resources.

DJ
Thursday, December 04, 2003

Aussie Chick,

I recommend http://peach.ease.lsoft.com/scripts/wa.exe?A0=visbas-l as an excellent VB list for this type of question.

Seeya

Matthew
Thursday, December 04, 2003

Aussie Chick,

As a side issue, I would replace:

tStyle.after_Initialise (tS.ReadAll)

with:

Call tStyle.after_Initialise (tS.ReadAll)
tStyle.after_Initialise tS.ReadAll

Your way would be slightly slower with no benefit.

Seeya

Matthew
Thursday, December 04, 2003

Aussie Chick,

For the above post:

Call tStyle.after_Initialise (tS.ReadAll)
tStyle.after_Initialise tS.ReadAll

should state:

Call tStyle.after_Initialise (tS.ReadAll)
OR
tStyle.after_Initialise tS.ReadAll

Seeya

Matthew
Thursday, December 04, 2003

Mathew, thanks for the link, I will check it out.

I made the changes top, and it cut the load time down from 30-40 seconds to 25-30seconds, which is better.

I am still trying to figure some ways to cut it down more, like only parsing the parts of the text file that are being used.

Aussie Chick
Friday, December 05, 2003

Aussie Chick,

<quote>
I am still trying to figure some ways to cut it down more, like only parsing the parts of the text file that are being used.
</quote>

From memory, the FSO is not the fastest way to go when dealing with files. You may get some speed improvement (though not sure how much) by moving back to the 'old' way of doing things using Open, Input etc...

Seeya

Matthew
Friday, December 05, 2003

At the risk of stating the obvious, VB6 doesn't do garbage collection as such.  It uses reference counting:  setting a variable to refer to an object increments its reference count, releasing the variable decrements it.  When the number of references to a particular object drops to zero, it's destroyed immediately, there and then.

Which Damian technically said, but it's good to be completely clear on this point.  (=  This is in contrast to garbage collection, in which you mark objects for disposal, but are never quite sure how long they're going to hang around in object limbo before they're destroyed.

Sam Livingston-Gray
Friday, December 05, 2003

I plan to dump FSO and use the 'old' way on advise from someone else.
However the only time the FSO is used is that single section of code, from them on it is just the string (or part there of) that is used.
That part of the code doesn't take much time at all (a split second) and is only ever run one single time.

I have knocked some more out by get rid of some dim statements.

ie
dim tF as filter
call addFilter(tF)


becomes:

call addFilter(new filter)

And am working on not having my arrays redim as much

ie
redim(16)
redim(32)
as opposed to redim for every new element.

Aussie Chick
Friday, December 05, 2003

Sam, I was reading an article about that earlier.

The article said that the referencecount is set to zero when the object is set = nothing, or goes out of focus.

I assumed this to mean if class A creates and instance of Class B, then when Class A is closed, Class B is automatically closed to?

Or should I have a terminate function on all my class to set every object to nothing?

Aussie Chick
Friday, December 05, 2003

Hi,

Your speed issue is not concerned with reference counting. The slow speed is because of the use of FSO. But to answer your question,

<QUOTE>
I assumed this to mean if class A creates and instance of Class B, then when Class A is closed, Class B is automatically closed to?
</QUOTE>

VB *never* leaves a dangling pointer/reference. It calls Release (IUnknown) on its own. And you do not have to keep track of the number of AddRefs (Set Thingy = New Foo) too and match them with the Release(s), whether they are through an interface (Set Dog = New IAnmial) or through object instantiation (CreateObject("MyLib.TelephoneIndex").

By closing If you mean setting the object A to Nothing, then the answer is Yes, if an object of class B is contained in class A, the setting the object of A to Nothing automatically would destroy B. However, if you are refering to some Close method for class A that you've written, then you would know best what's inside the method definition for the Close method of class A.

To reduce the speed, it would serve you best to use either the VB intrinsic functions for file handing as already suggested, or even better to go for the API (CreateFile, OpenFile, i.e. file I/O API routines or file mapping, as you may choose).

Sathyaish Chakravarthy
Friday, December 05, 2003

I would like to add that as a matter of practice, it is best to explicitly set children to Nothing within the parent objects. Whether you do this in the Close method of class A or the Class_Terminate event is upto you. A live implementation comes from ADODB.Recordset as in closing a recordset sets its child Fields collection to Nothing too and you don't have to bother about the contained objects within the Recordset object when you say rs.Close. What remains then is only setting the rs to Nothing.

Sathyaish Chakravarthy
Friday, December 05, 2003

That's not quite it. If an object B of class B is a member variable of object A (of class A), then when A is set to Nothing (or goes out of scope), object B will also go out of scope and cease to exist, *as long as no other object holds a reference to it*. But if you had earlier passed a reference to B to some other object C that was still around, B will survive the death of A, otherwise you would not be happy.

The thing to watch out for in VB is circular references, where A holds a reference to B, and B holds a reference to A. GC systems can generally recognise this situation and throw the whole shebang out, but reference-counting languages like VB get stuck, and the symbiotic pair persist in memory as long as your process is running. In this situation you have to put something in to explicitly release the resource at an opportune moment. A Form Closing event is often a reasonable place, for example.

One thing I found useful in the past was to put debug messages in my creation routines and destruction events for the major classes, so that you can see what is really going on.

Disclaimer - I am no expert in any of this. Corrections and clarifications from the more learned may well follow!

Dave Hallett
Friday, December 05, 2003

Or, indeed, get in before I press the Post Message button!

*sigh*

Dave Hallett
Friday, December 05, 2003

Thanks guys.

That answers my garbage collection question.

I am still working on speeding up the loading.
I have it from 45sec down to 20-25secs.

>Your speed issue is not concerned with reference >counting. The slow speed is because of the use of FSO.
I understand FSO is slower, however I do not use it other then to initially read the file, then I shut it down. I have tested to see how much time this takes up and it is only a split second of the 20+ second load time, so it is not my main concern yet.

If anyone can recommend any good webpages on increasing efficiency in VB6....

Aussie Chick
Friday, December 05, 2003

I recollect having seen some optimization tips on VB Helper. You can search the site at http://www.vbhelper.com, in the old site index which is in a left pane at the bottom of the home page.

Apart from that, you'll find some tips on this page and its links:
http://www.aivosto.com/vbtips/vbtips.html

Further, you can browse some VB sites such as mvps.org, vb-explorer and vbtt.com for some tips.

If FSO isn't the reason for the delay in execution, then you'll have to clean up some of your code, which is perhaps why you're asking.

Good Luck!

Sathyaish Chakravarthy
Friday, December 05, 2003

http://www.mvps.org/vbnet/index.html


Friday, December 05, 2003

Two things:

1) To answer the original question, closing the text stream just closes the text stream.  That doesn't have any effect on any other objects you might have in your program.

2) Note that the ReadAll method is somewhat inefficient for extremely large files.  It's very fast for small files, but when they get up there, it gets slower and slower.

Why's that? Well, internally, the FSO uses the same code to handle reading files as it does reading standard streams -- but of course, you can determine the size of a file ahead of time.  You _cannot_ determine the size of a standard stream ahead of time.  Since the ReadAll method uses an algorithm that ignores the fact that the stream size can be known, it is less efficient than it could be -- in the large file case, it ends up doing a lot of unnecessary large block allocations.  (It uses a double-when-full algorithm, which is pretty good, but it could be better.)

Though I long intended to, I never did get around to rewriting the underlying file stream code to take advantage of the fact that some streams are of known size. I apologize for the inconvenience. 

I your program is slow because of that ReadAll, you might consider getting rid of it.  Perhaps you can change your algorithm to parse a single line at a time?

If your program is slow for some other reason, well, there's not much I can do about that.  :-)

How large a file are we talking about here?

Eric Lippert
Friday, December 05, 2003

I should read more carefully.  You said it was a 40 KB file.  ReadAll should handle that no problem.

Eric Lippert
Friday, December 05, 2003

woohoo.
I checked out those links, download a demo of a product callled 'VB Watch' from one of them.
It profiled my code and showed that just about all my wasted time was due to me wrapping a 'dictionary' object to hold some constants.

Have changed it to a switch-case and suddenly it loads in no-time.

Thanks for your input guys.

Aussie Chick
Friday, December 05, 2003

Can you describe briefly what you were doing to the dictionary object that made it run slowly? 

Thanks!

Eric Lippert
Saturday, December 06, 2003

Sure, (do you have a vested interest in it?)

I had wrapped the dictionary object. the main reason for wrapping it was so that I wouldn't have to test whether the item exists. (code below):


'********************************
'my wrapper
'********************************
Private tDic As Scripting.Dictionary
Private Sub Class_Initialize()
    Set tDic = New Scripting.Dictionary
End Sub
Private Sub Class_Terminate()
    Set tDic = Nothing
End Sub

Public Function add(key As String, value As String)
    If (tDic.exists(key)) Then
        tDic.item(key) = value
    Else
        tDic.add key, value
    End If
End Function

'note:
'tdic.comparemode is not being encapuslated.

Public Function count() As Long
    count = tDic.count
End Function

Public Function exists(key As String) As Boolean
    exists = False
    If tDic.exists(key) Then
        exists = True
    End If
End Function

Public Function item(key As String) As String
    item = tDic.item(key)
End Function

Public Function items()
    items = tDic.items
End Function
Public Function key(oldKey As String, newKey As String)
    tDic.key(oldKey) = newKey
End Function

Public Function keys()
    keys = tDic.keys
End Function
Public Function remove(key As String)
    tDic.remove (key)
End Function

Public Function removeAll()
    tDic.removeAll
End Function
'********************************


As for what I was doing using the wrapped dictionary object for, well in my program I allow the user to make changes to a text file, which effects the program (the program reads the text file at run-time). I had allowed some constants in this text file to make it easier (and less error-prone).

when the program encountered a possible constant it would check the wrapped dictionary object (see below)

'**********************************
'my constants.cls
'**********************************
Option Explicit

Private Constants As CalebS_Dictionary_dll.data_collection


Private Sub Class_Initialize()
    Set Constants = New CalebS_Dictionary_dll.data_collection
   
    Constants.Add "LABELLEFT", "120"
    Constants.Add "LABELMIDLEFT", "2220"
    Constants.Add "LABELRLEFT", "3850"
    Constants.Add "LABELWIDTH_SM", "735"
    Constants.Add "LABELWIDTH_LG", "1215"
    Constants.Add "TEXTLEFT", "1320"
    Constants.Add "TEXTMIDLEFT", "2900"
    Constants.Add "TEXTRLEFT", "4465"
    Constants.Add "TEXTWIDTH_SM", "855"
    Constants.Add "TEXTWIDTH_MED", "2435"
    Constants.Add "TEXTWIDTH_LG", "4000"
    Constants.Add "TRUE", "1"
    Constants.Add "FALSE", "0"
End Sub

Public Function constant(constant_String As String) As Integer
    constant = 0
    constant_String = UCase(constant_String)
   
    'remove any spaces.
    Dim tC() As String
    tC = Split(constant_String)
    Dim ii As Integer
    For ii = 0 To UBound(tC)
        If tC(ii) <> " " And tC(ii) <> "" Then
            constant_String = tC(ii)
        End If
    Next ii
   
    If Constants.Exists(constant_String) Then
        constant = Val(Constants.Item(constant_String))
    ElseIf Val(constant_String) <> 0 Then
        constant = Val(constant_String)
    End If
End Function
'**********************************



The above has now all been replaced with the following to lop off 20seconds load time.
'**********************************
'my new constants module
'**********************************
Option Explicit
 
Public Function constant(constant_String As String) As Integer
    constant = 0
   
    'turn constant_string into uppercase, and remove any spaces
    constant_String = UCase$(constant_String)
    constant_String = Replace(constant_String, " ", "")
   
    Select Case constant_String
        Case "LABELLEFT":
            constant = 120
        Case "LABELMIDLEFT":
            constant = 2220
        Case "LABELRLEFT":
            constant = "3850"
        Case "LABELWIDTH_SM":
            constant = "735"
        Case "LABELWIDTH_LG":
            constant = "1215"
        Case "TEXTLEFT":
            constant = "1320"
        Case "TEXTMIDLEFT":
            constant = "2900"
        Case "TEXTRLEFT":
            constant = "4465"
        Case "TEXTWIDTH_SM":
            constant = "855"
        Case "TEXTWIDTH_MED":
            constant = "2435"
        Case "TEXTWIDTH_LG":
            constant = "4000"
        Case Else:
            constant = Val(constant_String)
    End Select
End Function
'**********************************

I am assuming that you have some interest in the dictionary object, how so?

Aussie Chick
Saturday, December 06, 2003

Eric Lippert is like the dude who wrote VB6!!!!!


Saturday, December 06, 2003

really? well that explains the interest then.


...that is kind of funny.

Aussie Chick
Saturday, December 06, 2003

Aussie Chick,

If anyone can recommend any good webpages on increasing efficiency in VB6.... ,

http://peach.ease.lsoft.com/scripts/wa.exe?A0=visbas-l

;-)

Seeya

Matthew
Sunday, December 07, 2003

Aussie Chick,

<quote>
The article said that the referencecount is set to zero when the object is set = nothing, or goes out of focus.
</quote>

To start with, I assume you mean scope rather than focus.

Many misunderstandings with VB are caused to do with lack of clarity when using terms - particularly in the help files.

For example, the help file does not clearly differentiate between objects and object variables. This can lead to problems such as seen in http://shorterlink.com/?8QGD6V .

Looking at your statement above though, it should be rephrased as follows:

The referencecount of an object is reduced by one whenever the object variable pointing to the object is set = nothing, or goes out of scope (which implicitly sets it to nothing). When the reference count of an object is <= 0, the object will 'terminate' itself.

Pedantic - possibly. ;-)

<quote>
I assumed this to mean if class A creates an instance of Class B, then when Class A is closed, Class B is automatically closed to?
</quote>

If the instance of Class B has a reference count of 1 (ie there is only one object variable pointing to it, and that object variable is part of the Class A instance), then the above statement is true.

<quote>
Or should I have a terminate function on all my class to set every object to nothing?
</quote>

It isn't required. Some people will argue it is required, but that is almost certainly due to bugs in old DAO versions - and that was generally due to not calling Close rather than not setting the object variable to Nothing.

If you do ever put code in a Terminate event handler, make sure you use On Error Resume Next. Because if any code in there raises an error (very unlikely on Set obj = Nothing, but anyway) then your app will crash.

Seeya
Matthew

Matthew
Sunday, December 07, 2003

>To start with, I assume you mean scope rather than focus.

yes you are write, and I know this term but it slipped my mind and scope popped in, I thought it was wrong but was being lazy.....

>Pedantic - possibly. ;-)
when dealing with syntactical issues I think pedantic is possibly a good thing.


Thanks for the tips, I am checking the site out now.

Aussie Chick
Monday, December 08, 2003

Dave,

<quote>
The thing to watch out for in VB is circular references, where A holds a reference to B, and B holds a reference to A. GC systems can generally recognise this situation and throw the whole shebang out, but reference-counting languages like VB get stuck, and the symbiotic pair persist in memory as long as your process is running. In this situation you have to put something in to explicitly release the resource at an opportune moment. A Form Closing event is often a reasonable place, for example.
</quote>

There are a few ways you can 'beat' circular references in VB. A good way is described at http://www.vb-faq.com/Articles/Hughson/proxyobjects.asp .

Seeya

Matthew
Monday, December 08, 2003

I helped implement VBScript, not VB6.  But I wrote most of the dictionary object, so I'm always interested in how people are using it.

Eric Lippert
Monday, December 08, 2003

You are right that your select-case statement will be much faster, particularly for such a small number of entries.  If the number of constants were in the hundreds or thousands, then a table-driven approach probably becomes both more efficient and definately becomes more managable.

The performance problem is likely gated by the overhead.  When you go with a select-case statement, the VB6 compiler can generate an efficient lookup table that rapidly compares each string.  What's killing you in the dictionary is likely the time required to set up the call into the ActiveX object -- and this is exacerbated by the fact that you've needlessly wrapped the object in an additional layer of inefficient indirection. 

As the problem becomes more complex -- as you add more and more constants -- the gating factor stops being the call overhead and starts being the string comparisons.  The dictionary object uses a much more efficient method for searching a _large_ body of values than the select-case statement.  For hundreds or thousands of items, the overhead of the call will be small compared to the cost savings of the more efficient search.

Actually looking at your programs, however, I see some problems. 

First of all, the two programs do not do the same thing.  The first program finds the last token in the string and processes that, whereas the second program removes all the spaces from the string and then does the comparison. 

For example, if the string were

"BLAH TRUE"

then the first program would split that into the array TC <-- {"BLAH", "TRUE"}, and then determine that TC(1) was "TRUE" and return 1.  But the second program would turn that into "BLAHTRUE" and not return 1.

So at least one of these programs doesn't do what you'd expect. 

Also, your second program uses numbers for some of the constants and strings for others.  The type system will do the conversion for you, but it would be better style to be consistent on this point.

Going through your first program, I see a lot of bizarre things.  Even though you've replaced it with something that works better, it might be instructive to go through some of the oddities of this first program.

First, I don't understand why you needed to wrap the object.  Yes, Add will give you an error if the object is already there, but you don't need to call Add.  It is perfectly legal to say

dict(key)=value

even if key was not previously in the collection -- the property accessor does that check for you.  I implemented Add so that if you WANTED to prevent duplicates from being added, you could.  If you don't want that, don't use it!  There's no need to work around this feature.

Second, what does that loop in the "constant" function do?  You are looking for the LAST string that matches that pattern on the line, is that right?  If that's the case, then why are you looking from the FRONT?  Start at the _end_ and quit out of the loop when you find a match -- that's a lot more efficient.

But either way, that's not what the comment says you're doing -- it says "remove all the spaces", but instead your tokenizing the string.  Which is intended? 

Third, why are you storing the values as strings in the dictionary and then converting them to numbers? Can't you just store them as numbers?  You can put ANYTHING into a dictionary.

Fourth, why are you checking to see if Val(constant_string) <> 0?  If it's not zero, you assign the value, if it is zero, you assign zero, so why not just assign it rather than having an If statement?

Anyway, I hope that helps.

Eric Lippert
Monday, December 08, 2003

>and this is exacerbated by the fact that you've >needlessly wrapped the object in an additional layer of >inefficient indirection. 
Agreed, I created the wrapper for another project, though even now I realise that the wrapper (especially being implemented as a .dll rather then just a class in the code) slows things down. Anyhow I guess I was not even thinking at the time that I didn't need the functionality that this wrapper provided. That and the fact that I still have a lot to learn about efficiency (ie in my mind it was neater code, therefore it was good, I did not even think that it would slows things down at all)

>So at least one of these programs doesn't do what you'd >expect. 
Yeh, I think I was struggling with a quick way to do some parsing at the time, but the second program was the correct one (she says as she goes back to check...)

>Also, your second program uses numbers for some of the >constants and strings for others
Thanks, that was my mistake (typo or lost track of what I was doing I guess)

I feel like a kid having my code picked to pieces, I try to tell myself that this is the first *real* program that I have ever written, still I feel dumb.(but appreciative all the same!)


>First, I don't understand why you needed to wrap the >object.  Yes, Add will give you an error if the object is >already there, but you don't need to call Add.  It is >perfectly legal to say
>
>dict(key)=value
I actually took the advise from someone else (http://oldlook.experts-exchange.com/Programming/Programming_Languages/Visual_Basic/Q_20708168.html) note this was a question I asked in relation to a macro I was writing for work (this being the time when I created the wrapper).

I just wanted to be able to say 'add this value and this key' and the dictionary object would do one of two things -->if the key existed then just change the value (ie dict(key) = value), else if the key did not exist in the collection, then add the new key with the value.
I just wanted to be able to put one line of code in my program-->dict.add(key, value), and let the program sort it out. I didn't want to have an if-else statement to test whether the object existed before I tried to add it (again note, that this wrapper was created for a set of macros I wrote for work and looking at it I don't know why I just didn't use the dictionary object straight, as that functionality was needed for this program).

>Second, what does that loop in the "constant" function >do?  You are looking for the LAST string that matches that >pattern on the line, is that right?  If that's the case, then >why are you looking from the FRONT?  Start at the _end_ >and quit out of the loop when you find a match -- that's a >lot more efficient.
>
>But either way, that's not what the comment says you're >doing -- it says "remove all the spaces", but instead your >tokenizing the string.  Which is intended?

do you mean this loop?
    'remove any spaces.
    Dim tC() As String
    tC = Split(constant_String)
    Dim ii As Integer
    For ii = 0 To UBound(tC)
        If tC(ii) <> " " And tC(ii) <> "" Then
            constant_String = tC(ii)
        End If
    Next ii

yes horrible, like I said I am learning, I was having troubles with the constant_string have surrounding spaces
ie " Left" <> "Left" <> " Left  " ..etc
I was tokenising it soley to be able to get down to the string with no spaces....I had not met the 'replace' function at that stage.
The code very quickly changed to something like:
constant_string = replace(constant_string, " ", "")
which you didn't see because in the meantime I changed it all to the select-case
really, I am learning...

>Third, why are you storing the values as strings in the >dictionary and then converting them to numbers? Can't >you just store them as numbers?  You can put ANYTHING >into a dictionary.
Noted. I just assumed the dictionary object was for strings...

>Fourth, why are you checking to see if Val (constant_string) <> 0?  If it's not zero, you assign the >value, if it is zero, you assign zero, so why not just assign >it rather than having an If statement?
Again, my only excuse is that I am learning, but I did notice this and change it when I switched to the select-case
ie
'first program
    If Constants.Exists(constant_String) Then
        constant = Val(Constants.Item(constant_String))
    ElseIf Val(constant_String) <> 0 Then
        constant = Val(constant_String)
    End If

'second program
        Case Else:
            constant = Val(constant_String)

Anyhow, thanks for your feedback it is much appreciated. Being at home by my computer does lead to a lot of mess if I am not careful (focused/thinking..) there would have to definetly be a benefit to working in an environment with experienced coders, so I really do appreciate you taking the time to give me some constructive critiscism.

Aussie Chick
Monday, December 08, 2003

Hey AC,

I didn't intend to make you feel like a little kid!  Your code has the right idea, by and large, but the devil is in the details.  I think you're on the right track.

> I just wanted to be able to say 'add this value and this
> key' and the dictionary object would do one of two
> things --if the key existed then just change the value
>  (ie dict(key) = value), else if the key did not exist in
>  the collection, then add the new key with the value.

Right -- "dict(key) = value" does exactly what you just described -- it checks to see if the key is there, replaces if it is, adds a new one if it is not.  So there's no need to wrap it.

Re: the Replace method -- you were on the right track with the "Split".  I implemented Split, which takes a string apart into an array, and Join, which takes an array and puts it back together into a string.  Do you know I implemented Replace? It simply Splits on the search string, then Joins the resulting array with the replace string! 

In my defence, I was young and foolish when I wrote that code -- it is not a very efficient search-and-replace algorithm! But it works well enough for most VBScript scenarios.

Eric Lippert
Monday, December 08, 2003

>Do you know I implemented Replace? It simply Splits on the search string, then Joins the resulting array with the replace string! 

I did not even know who you were until a few days ago. I am glad to talk to you though.
You definetly make me realise how far I have to go, but I am smart enough to know we all have to start somewhere!

I am also glad to here the workings behind the 'replace' function. As I have implemented a few classes that do different things (like a split function the will ignore anything inside a string character), and I have used the split class alot to do it.
In fact the split function is the main function I have used to parse a text file. I kind of wondered if I was going overboard using it, but it did the job. Knowing that the replace function is based on the spit/join functions makes me feel like I am doing okay..

I don't even have a single VB6 reference manual of any kind, thank goodness for the Internet (we live and learn).

If you knew just how many times in my code I was trying to use the split function but making my code so unreadable trying to avoid spaces and end of line characters.....well lets just say the replace function but my code alot prettier!

I really have appreciated your time. Thanks.

Aussie Chick
Tuesday, December 09, 2003

Eric,

<quote>
Re: the Replace method -- you were on the right track with the "Split".  I implemented Split, which takes a string apart into an array, and Join, which takes an array and puts it back together into a string.  Do you know I implemented Replace? It simply Splits on the search string, then Joins the resulting array with the replace string! 

In my defence, I was young and foolish when I wrote that code -- it is not a very efficient search-and-replace algorithm! But it works well enough for most VBScript scenarios.
</quote>

Always good to see such an excellent programmer highlight his own limitations! ;-)

BTW, did you write Replace for VBScript only, or also VB 6? VB 6 is also not the fastest implementation - particularly where the find and replace strings are the same length (fast enough for most cases though).

Seeya

Matthew
Tuesday, December 09, 2003

Matthew, You're an annoying piece of shit.  Just to let you know.  You push yourself off as an expert and you have a huge fucking head.  Take a pin and pop it.


Wednesday, December 10, 2003

??What kind of person writes stuff like that??

How rude.

Aussie Chick
Wednesday, December 10, 2003

<blank>,

<quote>
You push yourself off as an expert <snip>
</quote>

Apologies if I gave that impression. That was not my intent. I was just trying to give some assistance and learn something from Eric (whose blog I regularly read, BTW) along the way.

I was not trying to 'push myself off' as anything. Feel free to email me offline (click on my Matthew below to contact me) if you would like to discuss this further.

Seeya

Matthew
Wednesday, December 10, 2003

Eric has a blog.

Can you give me a link please?

Aussie Chick
Thursday, December 11, 2003

Aussie Chick,

<quote>
Eric has a blog.

Can you give me a link please?
</quote>

http://blogs.gotdotnet.com/ericli/

Though (as it says on his site) it will soon be moving. Eric's is one of the more interesting blogs out there. His blogroll (on the right side of the page) will give you some other blogs to check out as well...

Seeya

Matthew
Thursday, December 11, 2003

> did you write Replace for VBScript only,
> or also VB 6?

Yes, the VB6 implementations of Join, Split, InstrRev, etc, are basically direct ports of the code I wrote for VBScript, with only a few minor modifications.

In fact, originally the VBScript and VBA implementations were going to share quite a bit of code, including a shared runtime library.  For various technical and organazational reasons, that never panned out.  One of the first things I did as a FTE was to rename RADRUN.DLL (for "Rapid Application Development Runtime") to SCRRUN.DLL. 

Tufte points out in his course on graphic design that newspapers and magazines tend to be laid out to reflect the organization that produces them -- the same is true with software!  Names of libraries, namespaces, etc, often reflect the hierarchy that produced them.

I should write a blog entry on that sometime...

Speaking of which, I'm glad you like my blog.  Once it's moved over to the new site I'll be updating it more often.  Do let me know if there are topics you'd like to hear about.

Eric Lippert
Thursday, December 11, 2003

Eric,

<quote>
I should write a blog entry on that sometime...
</quote>

Looking forward to it! ;-)

Seeya

Matthew
Thursday, December 11, 2003

Hey, Im a new VB user, one of my friends got me started with it, and i cant get the compiler he sent me to work on my computer, so do know of any good freeware compilers that i could download to see if im going to get seriously into it? thanks

~Scott

Scott J House
Sunday, August 01, 2004

*  Recent Topics

*  Fog Creek Home