Home All Groups Group Topic Archive Search About

Advice on storage and retrieval

Author
9 May 2007 11:29 PM
MP
Hi,
two part question
part1
I have a simple app to search files
Enter string in text box, pick commandbutton, it searches certain files for
matching text.
Now I thought to add a feature, Save list of previous searches
change from textbox to combo box, combo loads with previous saved (somehow)
list, pick from list or enter new search, save new search to list if not
already on list
(similar to recent sites list in browser target combo box, )
so i thought of saving to ini file

[SavedSearchesSection]
    Search0=FirstSearch
    Search1=SecondSearch
    etc

question1
is that a normal way to setup incremental/indexed keynames? or am i using
ini in wrong way?
come to think of it, the search term itself could become the key and I
wouldn't need even a value!???

part2
thinking out loud ....<g>
- seems too small a need to bother with a database solution
- could also just use simple text file
- suppose I could create a class, make persistable, save prop list with prop
bag, ???
    haven't tried that yet, that might be fun
it fits in with my desire to become more object oriented <g>
also fits with my recent contemplations of how to create a generic Key/Data
storage class

In nearly every tool i write I need to save key/data pairs for various
reasons.
have used arrays, collections, scripting.dicitionaries, Olaf's
dhSortedDictionary (very nice, thanks Olaf!!!), databases, ini files etc.
I'd like to structure a class that I could reuse with very simple calls and
not worry about re-implementing storage functions in every different app...
If Not cStore.Exists(SearchTerm) Then cStore.Add(SearchTerm)
or
If Not cStore.Exists(Key) Then cStore.Add(Key, Data) or something like that
And if i created an interface, i could make various implementations to use
various storage methods, ini, database, etc according to different need
levels(eg is persistance req'd or in-memory sufficient, ...simple key/data
pair adequate or do we need tables/fields/records detail...)

question2
any thoughts / advice?
Show quoteHide quote
:-)
Mark

Author
10 May 2007 4:44 AM
MP
"MP" <NoSpam@Thanks.Com> wrote in message
news:OqznbHpkHHA.1532@TK2MSFTNGP03.phx.gbl...

> part2

> also fits with my recent contemplations of how to create a generic
Key/Data
> storage class

well, here's a first attempt at an interface and implementation using
collection
probably not efficient but seems to work in limited test shown below
other implementations could use arrays/etc to improve efficiency i'm sure
also need to add .Save property to persist data somehow and .Restore to
retrieve saved data....???

comments welcome
Thanks
Mark

'-----------------------------------------
IDataStore.cls
Option Explicit
Public Property Get Count() As Long
End Property
Public Property Get Keys() As Variant
End Property
Public Property Get Values() As Variant
End Property
Public Property Get Data(Key As String) As Variant
End Property
Public Sub Add(Key As String, Data As Variant)
End Sub
Public Sub Remove(Key As String)
End Sub
Public Function Exists(Key As String) As Boolean
End Function
'-----------------------------------------

'-----------------------------------------
cDataStore.cls
Option Explicit
Implements IDataStore
Private mcolKeys As Collection
Private mcolData As Collection

Private Sub Class_Initialize()
Set mcolKeys = New Collection
Set mcolData = New Collection
End Sub

Private Sub Class_Terminate()
Set mcolKeys = Nothing
Set mcolData = Nothing
End Sub

Private Sub IDataStore_Add(Key As String, Data As Variant)
Dim sTest As Variant
On Error Resume Next
  sTest = mcolKeys.Item(Key)

  If Err Then
      Err.Clear
      mcolKeys.Add Key, Key
      mcolData.Add Data, Key
    Else
      mcolData.Remove Key
      mcolData.Add Data, Key
  End If

On Error GoTo 0

End Sub

Private Property Get IDataStore_Count() As Long

  IDataStore_Count = mcolData.Count

End Property

Private Property Get IDataStore_Data(Key As String) As Variant

  IDataStore_Data = mcolData.Item(Key)

End Property

Private Function IDataStore_Exists(Key As String) As Boolean
Dim s As String

On Error Resume Next
  s = mcolKeys.Item(Key)

  If Err Then
        Err.Clear
      Else
        IDataStore_Exists = True

  End If
  On Error GoTo 0
End Function

Private Property Get IDataStore_Keys() As Variant
Dim i As Long
Dim a() As String
ReDim a(mcolKeys.Count - 1)

For i = 1 To mcolKeys.Count
  a(i - 1) = mcolKeys.Item(i)
Next i

IDataStore_Keys = a

End Property

Private Sub IDataStore_Remove(Key As String)
On Error Resume Next
  mcolData.Remove Key

  If Err Then
    Err.Clear
  Else
    mcolKeys.Remove Key
  End If

  On Error GoTo 0
End Sub

Private Property Get IDataStore_Values() As Variant
Dim i As Long
Dim a() As Variant
ReDim a(mcolData.Count - 1)

For i = 1 To mcolData.Count
  a(i - 1) = mcolData.Item(i)
Next i

IDataStore_Values = a

End Property

'-----------------------------------------

'-----------------------------------------
'test.bas
'(replace LogEntry with Debug.Print)

Sub testdatastore()
'LogIn "testdatastore", True

Dim ostore As IDataStore
Set ostore = New cDataStore

Dim i As Integer
Dim j As Integer
Dim v As Variant
Dim sKey As String
Dim lMax As Long
Dim bReport As Boolean
'bReport = True ' to see keys/values but of course slows it way down

lMax = 250

'test add
For i = 0 To lMax
  ostore.Add CStr(i), "Test" & i
Next i

'test keys/values
If bReport Then
  LogEntry "List Keys"
  For Each v In ostore.Keys
    LogEntry "Key: " & CStr(v)
  Next
  LogEntry "List values"
  For Each v In ostore.Values
    LogEntry "Val: " & CStr(v)
  Next
End If

'test remove
For j = 1 To lMax Step 2
  ostore.Remove CStr(j)
Next

If bReport Then
  LogEntry "After remove"
  LogEntry "List Keys"
  For Each v In ostore.Keys
    LogEntry "Key: " & CStr(v)
  Next
  LogEntry "List values"
  For Each v In ostore.Values
    LogEntry "Val: " & CStr(v)
  Next
End If

'test exists
sKey = "28"

If ostore.Exists(sKey) Then
  LogEntry "Found key " & sKey
  LogEntry ostore.Data(sKey)
Else
  LogEntry "Key not found " & sKey
End If

Set ostore = Nothing

'LogOut

End Sub
Author
10 May 2007 6:55 AM
Steve Gerrard
Show quote Hide quote
"MP" <NoSpam@Thanks.Com> wrote in message
news:%23Sfcy3rkHHA.1624@TK2MSFTNGP02.phx.gbl...
>
> "MP" <NoSpam@Thanks.Com> wrote in message
> news:OqznbHpkHHA.1532@TK2MSFTNGP03.phx.gbl...
>
>> part2
>
> well, here's a first attempt at an interface and implementation using
> collection
> probably not efficient but seems to work in limited test shown below

> Private Property Get IDataStore_Values() As Variant
> Dim i As Long
> Dim a() As Variant
> ReDim a(mcolData.Count - 1)
>
> For i = 1 To mcolData.Count
>  a(i - 1) = mcolData.Item(i)
> Next i
>
> IDataStore_Values = a
>
> End Property

Here's a tip on using a collection. The above would be more efficent if you made
this change:

Dim v As Variant

i = 0
For Each v In mcolData
    a(i) = v
    i = i + 1
Next v

The For Each construct is much faster than indexing your way through a
collection.
Author
10 May 2007 7:25 AM
MP
Show quote Hide quote
"Steve Gerrard" <mynameh***@comcast.net> wrote in message
news:d_6dnacv4uxKXN_bnZ2dnUVZ_gCdnZ2d@comcast.com...
>
> "MP" <NoSpam@Thanks.Com> wrote in message
> news:%23Sfcy3rkHHA.1624@TK2MSFTNGP02.phx.gbl...
> >
> > "MP" <NoSpam@Thanks.Com> wrote in message
> > news:OqznbHpkHHA.1532@TK2MSFTNGP03.phx.gbl...
> >
> >> part2
> >
>
> Here's a tip on using a collection. The above would be more efficent if
you made
> this change:
>
> Dim v As Variant
>
> i = 0
> For Each v In mcolData
>     a(i) = v
>     i = i + 1
> Next v
>
> The For Each construct is much faster than indexing your way through a
> collection.
>

Thanks, I always forget that somehow because early on I learned that
variants were bad (inefficient) and since the iterator had to be a variant I
got away from doing that.

Mark
Author
10 May 2007 7:37 AM
Steve Gerrard
"MP" <NoSpam@Thanks.Com> wrote in message
news:%23Sfcy3rkHHA.1624@TK2MSFTNGP02.phx.gbl...
>
>
> well, here's a first attempt at an interface
>
> '-----------------------------------------
> IDataStore.cls
> Option Explicit
> Public Property Get Keys() As Variant
> Public Property Get Values() As Variant
> Public Property Get Data(Key As String) As Variant
> Public Sub Add(Key As String, Data As Variant)

For someone who wants to get more OO, you seem to like Variants a lot. Are you
really VO? :)

For your pondering:

I have done an entire engineering app around objects that implement this simple
interface:

' IListItem
Public Property Get Key() As Long
End Property

Public Function CompareTo(Item As IListItem) As Long
End Property

These can be added to a custom CList class object. The list can contain objects
that are all the same class, or a mixture, as long as they all implement
IListItem. The list can be sorted, using the CompareTo function of each object
(it uses a QuickSort and an index internally). It knows how to get the key of
each object, since they are all IListItems. It can quickly return the next or
previous item from any object in the list. I chose Long keys for performance
reasons, but you could certainly use String keys if you preferred.

It might seem silly to create a Class that just has one string property called
Text, and implements IListItem. I wouldn't hesitate for a second to do it,
though, for three reasons:
1) I would instantly have a nicely managed, sortable list of strings by using a
CList;
2) I could add them to any CList, including one that had other classes of
objects in it;
3) Every class I have ever made ends up aquiring more properties over time, and
usually it doesn't take long. Abbr (abbreviation); Caption; MaxLength, etc.

I found it more useful not to have a list interface, but rather to embed a CList
inside any class that needed one. For example, CMaterials manages a list of
materials, by using an embedded CList object. It is easy to pass through to
CList when appropriate, and it can intervene and do material-related things
whenever needed. This is the low-tech way to do inheritance in VB.
Author
10 May 2007 1:06 PM
MP
Show quote Hide quote
"Steve Gerrard" <mynameh***@comcast.net> wrote in message
news:K6WdnTPPrOg9Vt_bnZ2dnUVZ_sSmnZ2d@comcast.com...
>
> "MP" <NoSpam@Thanks.Com> wrote in message
> news:%23Sfcy3rkHHA.1624@TK2MSFTNGP02.phx.gbl...
> >
> >
> > well, here's a first attempt at an interface
> >
> > '-----------------------------------------
> > IDataStore.cls
> > Option Explicit
> > Public Property Get Keys() As Variant
> > Public Property Get Values() As Variant
> > Public Property Get Data(Key As String) As Variant
> > Public Sub Add(Key As String, Data As Variant)
>
> For someone who wants to get more OO, you seem to like Variants a lot. Are
you
> really VO? :)
>

:-) sure looks like that eh?
well, i was just looking to get a list of the keys/ and or data/ if that was
required by calling operation,
since you can't assign to an array I've always seen variant used for return,
then i was thinking to store "anything" in the data, the Data item property
had to be variant also to avoid type mismatch or ETC
I guess in that interface i was already thinking about implemening using
collections and since collection items are variant...and so on....
<g>



> For your pondering:
>
> I have done an entire engineering app around objects that implement this
simple
> interface:
>
> ' IListItem
> Public Property Get Key() As Long
> End Property
>
> Public Function CompareTo(Item As IListItem) As Long
> End Property
>

I assume that's just part of the interface???
Doesnt' there have to be an .Item property also?
otherwise how do you get at the actual thing in itself?
wouldn't that have to be As Variant to allow any object?
and an .Add etc....


Show quoteHide quote
> These can be added to a custom CList class object. The list can contain
objects
> that are all the same class, or a mixture, as long as they all implement
> IListItem. The list can be sorted, using the CompareTo function of each
object
> (it uses a QuickSort and an index internally). It knows how to get the key
of
> each object, since they are all IListItems. It can quickly return the next
or
> previous item from any object in the list. I chose Long keys for
performance
> reasons, but you could certainly use String keys if you preferred.
>
> It might seem silly to create a Class that just has one string property
called
> Text, and implements IListItem. I wouldn't hesitate for a second to do it,
> though, for three reasons:
> 1) I would instantly have a nicely managed, sortable list of strings by
using a
> CList;
> 2) I could add them to any CList, including one that had other classes of
> objects in it;
> 3) Every class I have ever made ends up aquiring more properties over
time, and
> usually it doesn't take long. Abbr (abbreviation); Caption; MaxLength,
etc.
>
> I found it more useful not to have a list interface, but rather to embed a
CList
> inside any class that needed one. For example, CMaterials manages a list
of
> materials, by using an embedded CList object. It is easy to pass through
to
> CList when appropriate, and it can intervene and do material-related
things
> whenever needed. This is the low-tech way to do inheritance in VB.

I assume you mean inside the cMaterials you have
Private oList as cList
....
Sub Initialize()
Set oList = New cList ...or something similar

where cList is a collection class of type IListItem?

Thanks for the food for thought,

Show quoteHide quote
:-)
Mark

>
>
>
>
Author
10 May 2007 3:19 PM
Steve Gerrard
Show quote Hide quote
"MP" <NoSpam@Thanks.Com> wrote in message
news:ekb%231PwkHHA.3704@TK2MSFTNGP02.phx.gbl...
>
>
> :-) sure looks like that eh?
> well, i was just looking to get a list of the keys/ and or data/ if that was
> required by calling operation,
> since you can't assign to an array I've always seen variant used for return,
> then i was thinking to store "anything" in the data, the Data item property
> had to be variant also to avoid type mismatch or ETC
> I guess in that interface i was already thinking about implemening using
> collections and since collection items are variant...and so on....
> <g>
>

I think my points were

1) you may get more use out of an interface if you think about using it for the
things being added to the collection or list, rather than for the list or
collection class itself

2) you can make classes for storing "anything", and if they implement the right
interface, you can store any of them in your collection or list.
Author
10 May 2007 4:30 PM
MP
Show quote Hide quote
"Steve Gerrard" <mynameh***@comcast.net> wrote in message
news:msadnVf-gZR1qt7bnZ2dnUVZ_hynnZ2d@comcast.com...
>
> "MP" <NoSpam@Thanks.Com> wrote in message
> news:ekb%231PwkHHA.3704@TK2MSFTNGP02.phx.gbl...
> >
> >
> > :-) sure looks like that eh?
> > well, i was just looking to get a list of the keys/ and or data/ if that
was
> > required by calling operation,
> > since you can't assign to an array I've always seen variant used for
return,
> > then i was thinking to store "anything" in the data, the Data item
property
> > had to be variant also to avoid type mismatch or ETC
> > I guess in that interface i was already thinking about implemening using
> > collections and since collection items are variant...and so on....
> > <g>
> >
>
> I think my points were
>
> 1) you may get more use out of an interface if you think about using it
for the
> things being added to the collection or list, rather than for the list or
> collection class itself
>
> 2) you can make classes for storing "anything", and if they implement the
right
> interface, you can store any of them in your collection or list.
>

Hi Steve,
appreciate your hanging in there with me...
trying to understand it all and get it in my pea brain <g>

to go with your idea
Interface:
    IListItem
Properties
    Key as Long (or string)
' here I'm still confused....
    ...don't I need Item (as variant) to store and return the actual "thing"
that was stored????
           ... and doens't it have to be as Variant so different
implementations can store different types???
        cIntList, cStringList, cObjectList, etc????


or are you saying the .Item property only goes in the concrete class
implementation?
so in cStringList for example I'd have
..Item as String
???

then in the implementation class are you still using Collection to store the
cListItems????
what about a Save and Restore method pair for persistence?
would that also want to live in the IListItem interface???

sorry just a little dense here...
appreciate your help and ideas!
Show quoteHide quote
:-)
Mark
Author
11 May 2007 4:04 AM
Steve Gerrard
Show quote Hide quote
"MP" <NoSpam@Thanks.Com> wrote in message
news:ek99%23BykHHA.4248@TK2MSFTNGP06.phx.gbl...
>
> "Steve Gerrard" <mynameh***@comcast.net> wrote in message
> news:msadnVf-gZR1qt7bnZ2dnUVZ_hynnZ2d@comcast.com...
>>
>> "MP" <NoSpam@Thanks.Com> wrote in message
>> news:ekb%231PwkHHA.3704@TK2MSFTNGP02.phx.gbl...
>> >
>> >
> Hi Steve,
> appreciate your hanging in there with me...
> trying to understand it all and get it in my pea brain <g>
>
> to go with your idea
> Interface:
>    IListItem
> Properties
>    Key as Long (or string)
> ' here I'm still confused....
>    ...don't I need Item (as variant) to store and return the actual "thing"
> that was stored????
>           ... and doens't it have to be as Variant so different
> implementations can store different types???
>        cIntList, cStringList, cObjectList, etc????
>
>
> or are you saying the .Item property only goes in the concrete class
> implementation?
> so in cStringList for example I'd have
> .Item as String
> ???
>
> then in the implementation class are you still using Collection to store the
> cListItems????
> what about a Save and Restore method pair for persistence?
> would that also want to live in the IListItem interface???
>

Closer, but no cigar yet :)

(And by the way, this is but one of many ways to skin this cat, I'm not
suggesting it is the one and only).

You are mixing up the IListItem group of classes (things that go into the list),
with the List class itself.
There would be no cStringList, or cWidgetList, or whatever. There is just CList.

Rather, the objects getting put in the list implement an interface. This means
that only objects can be added; hence the other post on why I would bother to
create a class that had just a single string property.

So you would have your own CString class, and a CWidget class, and what have
you. As long as each of these classes implements IListItem, they can be added to
any CList, and retrieved, and removed, etc. CList would have the Item method,
which would retrieve an object from the list by key. And it would return it as
an IListItem, since that is what it knows it to be.

Clear as mud yet?
Author
11 May 2007 12:03 PM
Ralph
Show quote Hide quote
"Steve Gerrard" <mynameh***@comcast.net> wrote in message
news:BI2dnfcxbeXOdt7bnZ2dnUVZ_rCsnZ2d@comcast.com...
>
> "MP" <NoSpam@Thanks.Com> wrote in message
> news:ek99%23BykHHA.4248@TK2MSFTNGP06.phx.gbl...
> >
> > "Steve Gerrard" <mynameh***@comcast.net> wrote in message
> > news:msadnVf-gZR1qt7bnZ2dnUVZ_hynnZ2d@comcast.com...
> >>
> >> "MP" <NoSpam@Thanks.Com> wrote in message
> >> news:ekb%231PwkHHA.3704@TK2MSFTNGP02.phx.gbl...
> >> >
> >> >
> > Hi Steve,
> > appreciate your hanging in there with me...
> > trying to understand it all and get it in my pea brain <g>
> >
> > to go with your idea
> > Interface:
> >    IListItem
> > Properties
> >    Key as Long (or string)
> > ' here I'm still confused....
> >    ...don't I need Item (as variant) to store and return the actual
"thing"
> > that was stored????
> >           ... and doens't it have to be as Variant so different
> > implementations can store different types???
> >        cIntList, cStringList, cObjectList, etc????
> >
> >
> > or are you saying the .Item property only goes in the concrete class
> > implementation?
> > so in cStringList for example I'd have
> > .Item as String
> > ???
> >
> > then in the implementation class are you still using Collection to store
the
> > cListItems????
> > what about a Save and Restore method pair for persistence?
> > would that also want to live in the IListItem interface???
> >
>
> Closer, but no cigar yet :)
>
> (And by the way, this is but one of many ways to skin this cat, I'm not
> suggesting it is the one and only).
>
> You are mixing up the IListItem group of classes (things that go into the
list),
> with the List class itself.
> There would be no cStringList, or cWidgetList, or whatever. There is just
CList.
>
> Rather, the objects getting put in the list implement an interface. This
means
> that only objects can be added; hence the other post on why I would bother
to
> create a class that had just a single string property.
>
> So you would have your own CString class, and a CWidget class, and what
have
> you. As long as each of these classes implements IListItem, they can be
added to
> any CList, and retrieved, and removed, etc. CList would have the Item
method,
> which would retrieve an object from the list by key. And it would return
it as
> an IListItem, since that is what it knows it to be.
>
> Clear as mud yet?
>

Perhaps its time to explain the difference between "is a kind of" and "uses
a"?

-ralph
<g>
Author
14 May 2007 2:21 PM
MP
Show quote Hide quote
"Steve Gerrard" <mynameh***@comcast.net> wrote in message
news:BI2dnfcxbeXOdt7bnZ2dnUVZ_rCsnZ2d@comcast.com...
>
> >
> So you would have your own CString class, and a CWidget class, and what
have
> you. As long as each of these classes implements IListItem, they can be
added to
> any CList, and retrieved, and removed, etc. CList would have the Item
method,
> which would retrieve an object from the list by key. And it would return
it as
> an IListItem, since that is what it knows it to be.
>
> Clear as mud yet?
>

Ah now I see, as the blind carpenter said...
:-)

Thanks
Mark
Author
14 May 2007 3:55 PM
Steve Gerrard
Show quote Hide quote
"MP" <NoSpam@Thanks.Com> wrote in message
news:eTqVuMjlHHA.3760@TK2MSFTNGP05.phx.gbl...
>
> "Steve Gerrard" <mynameh***@comcast.net> wrote in message
> news:BI2dnfcxbeXOdt7bnZ2dnUVZ_rCsnZ2d@comcast.com...
>>
> > >
>> So you would have your own CString class, and a CWidget class, and what
>>
>> Clear as mud yet?
>>
>
> Ah now I see, as the blind carpenter said...
> :-)
>

More generally, I find it much more useful to have interfaces for the small item
classes, than to have them for collection classes.

Once you have a collection of items, you can pass that around to various other
widgets for processing.

If you made a class called CStoreTextFile, for instance, it could have a method
called StoreThis(List as CList, FileName As String) that would store the
contents of the list in a text file.  Make another class called CStoreIniFile,
with a method called StoreThis(List as CList, IniName As String), that stores
the list in an ini file. And another called CStoreMDB, with a method called
StoreThis(List as CList, MDBName as String), etc.

You don't really need an interface to the storage classes, or to the list
classes. You end up with just a few of those anyway. What you need is interfaces
to the item classes, because you may have hundreds or thousands of such objects.
Author
14 May 2007 7:30 PM
MP
Show quote Hide quote
"Steve Gerrard" <mynameh***@comcast.net> wrote in message
news:hvqdnR0ai6zDG9XbnZ2dnUVZ_segnZ2d@comcast.com...
>
> "MP" <NoSpam@Thanks.Com> wrote in message
> news:eTqVuMjlHHA.3760@TK2MSFTNGP05.phx.gbl...
> >
> > "Steve Gerrard" <mynameh***@comcast.net> wrote in message
> > news:BI2dnfcxbeXOdt7bnZ2dnUVZ_rCsnZ2d@comcast.com...
> >>
> > > >
> >> So you would have your own CString class, and a CWidget class, and what
> >>
> >> Clear as mud yet?
> >>
> >
> > Ah now I see, as the blind carpenter said...
> > :-)
> >
>
> More generally, I find it much more useful to have interfaces for the
small item
> classes, than to have them for collection classes.
>
> Once you have a collection of items, you can pass that around to various
other
> widgets for processing.
>
> If you made a class called CStoreTextFile, for instance, it could have a
method
> called StoreThis(List as CList, FileName As String) that would store the
> contents of the list in a text file.  Make another class called
CStoreIniFile,
> with a method called StoreThis(List as CList, IniName As String), that
stores
> the list in an ini file. And another called CStoreMDB, with a method
called
> StoreThis(List as CList, MDBName as String), etc.
>
> You don't really need an interface to the storage classes, or to the list
> classes. You end up with just a few of those anyway. What you need is
interfaces
> to the item classes, because you may have hundreds or thousands of such
objects.
>
>

Got it.
Thanks again
Mark
Author
15 May 2007 1:50 AM
Larry Serflaten
"Steve Gerrard" <mynameh***@comcast.net> wrote

> More generally, I find it much more useful to have interfaces for the small item
> classes, than to have them for collection classes.

<snipped for brievity>

> You don't really need an interface to the storage classes, or to the list
> classes. You end up with just a few of those anyway. What you need is interfaces
> to the item classes, because you may have hundreds or thousands of such objects.

What I hear you saying is that over a few years time, where a person might use a
few hundred different types of UDTs (list items) they could use a class that implements
the IListItem, customized to include the needed members.

The downside to that is the case where you need only a simple list of intrinsic types.
If you want to store a 2, for example, you wrap it up in an object, if you want to store
a string, it also gets wrapped up in an object.  You loose the ability to provide the
most efficient storage method for the data type, because everything is held in an object.

Also, if you have items that have multiple unique members, you need a custom storage
class to store those members.  You may very well end up with as many storage classes
as you have ListItem classes.

For the 'generic list interface' method I mentioned, each implementation can store the
data in whatever structure is best suited for the job, and can provide access to multiple
members directly from the data.

If I were to use your IListItem idea, it would also include LineData property that would
serialize and de-serialize the item for easy storage to and from the disk.  With that property
included, any component that used a collection of list items, would also be able to easily
load and save the list to a file.  That would not eliminate the need to store everything in
an object, but it would reduce the number of different storage classes needed to store
lists of different items....

FWIW
LFS
Author
15 May 2007 2:25 AM
Steve Gerrard
Show quote Hide quote
"Larry Serflaten" <serfla***@usinternet.com> wrote in message
news:O30XKNplHHA.568@TK2MSFTNGP02.phx.gbl...
>
> "Steve Gerrard" <mynameh***@comcast.net> wrote
>
>> More generally, I find it much more useful to have interfaces for the small
>> item
>> classes, than to have them for collection classes.
>
> <snipped for brievity>
>
>> You don't really need an interface to the storage classes, or to the list
>> classes. You end up with just a few of those anyway. What you need is
>> interfaces
>> to the item classes, because you may have hundreds or thousands of such
>> objects.
>
> What I hear you saying is that over a few years time, where a person might use
> a
> few hundred different types of UDTs (list items) they could use a class that
> implements
> the IListItem, customized to include the needed members.
>

Yup.

> The downside to that is the case where you need only a simple list of
> intrinsic types.
> If you want to store a 2, for example, you wrap it up in an object, if you
> want to store
> a string, it also gets wrapped up in an object.  You loose the ability to
> provide the
> most efficient storage method for the data type, because everything is held in
> an object.
>

Yup. I claimed in an earlier post that it might make sense to make a class for a
string, if in time you end up needing a caption, an abbreviation, or other such
"additional" properties of the string. But the concept is not much use for
intrinsic data types. I guess I find that I rarely have a bit of data that is
really "all by itself".

>
> If I were to use your IListItem idea, it would also include LineData property
> that would
> serialize and de-serialize the item for easy storage to and from the disk.
> With that property
> included, any component that used a collection of list items, would also be
> able to easily
> load and save the list to a file.  That would not eliminate the need to store
> everything in
> an object, but it would reduce the number of different storage classes needed
> to store
> lists of different items....
>

Have you been peeking at my code? :)

I indeed have expanded IListItem to include data storage and retrieval
interfacing.

I went with a method called MapProperties. My big axe to grind was that I was
sick of having two places to specify the mapping of between the string name and
the actual variable in the class. Too many debugging sessions finding where the
spelling was one character different going out than coming in. So MapProperties
works for both reading the class data from storage, and writing the data out to
storage.

I'm happy  to give details if anyone is interested, but it is a bit elaborate.
Works like a charm though. I have been storing in an mdb file, since I can store
multiple collections by using a suitable GroupID, and use queries to retrieve
the one of interest. I'm sure it could be done with text files or ini files the
same way.
Author
10 May 2007 6:04 AM
J French
Show quote Hide quote
On Wed, 9 May 2007 18:29:13 -0500, "MP" <NoSpam@Thanks.Com> wrote:

>Hi,
>two part question
>part1
>I have a simple app to search files
>Enter string in text box, pick commandbutton, it searches certain files for
>matching text.
>Now I thought to add a feature, Save list of previous searches
>change from textbox to combo box, combo loads with previous saved (somehow)
>list, pick from list or enter new search, save new search to list if not
>already on list
>(similar to recent sites list in browser target combo box, )
>so i thought of saving to ini file
>
>[SavedSearchesSection]
>    Search0=FirstSearch
>    Search1=SecondSearch
>    etc
>
>question1
>is that a normal way to setup incremental/indexed keynames? or am i using
>ini in wrong way?
>come to think of it, the search term itself could become the key and I
>wouldn't need even a value!???

Either would be fine
Your only decision is whether to use a standard INI file format or
something of your own (call it CFG)
- there are advantages in using your own format, one of which is
having multiple fields with the same key name.

Personally I would not use the Win APIs for INI file management

Show quoteHide quote
>part2
>thinking out loud ....<g>
>- seems too small a need to bother with a database solution
>- could also just use simple text file
>- suppose I could create a class, make persistable, save prop list with prop
>bag, ???
>    haven't tried that yet, that might be fun
>it fits in with my desire to become more object oriented <g>
>also fits with my recent contemplations of how to create a generic Key/Data
>storage class

>In nearly every tool i write I need to save key/data pairs for various
>reasons.
>have used arrays, collections, scripting.dicitionaries, Olaf's
>dhSortedDictionary (very nice, thanks Olaf!!!), databases, ini files etc.
>I'd like to structure a class that I could reuse with very simple calls and
>not worry about re-implementing storage functions in every different app...
>If Not cStore.Exists(SearchTerm) Then cStore.Add(SearchTerm)
>or
>If Not cStore.Exists(Key) Then cStore.Add(Key, Data) or something like that
>And if i created an interface, i could make various implementations to use
>various storage methods, ini, database, etc according to different need
>levels(eg is persistance req'd or in-memory sufficient, ...simple key/data
>pair adequate or do we need tables/fields/records detail...)

I would not use anything more complicated than needed
- initially keep all the data in a vbCrLf delineated String and write
a few routines for inserting, getting, removing the data

It is just InStr Mid$ etc

Eventually you'll probably wrap that in a Class, but mostly you'll
just use it directly

Storage, at its crudest are two Functions/Subs

    Data$ = FileStr( FileName$ )
and
    Call StrFile( Data$, FileName$ )

IMO one needs to work on the 'little' utilities that one will use all
over the place
- gradually, as needed, one writes wrappers around them, but really
useful re-useable utilities tend to be pretty simple

In short, Apps should be designed from top down, but generic utilities
should be designed from the bottom up.  
- that way you get more re-useability
Author
10 May 2007 6:40 AM
MP
Hi J
Thanks for the response and sage advice.

if I had a blackboard I would write this 10,000 times

"I would not use anything more complicated than needed"

maybe then I'd learn <g>


Show quoteHide quote
"J French" <erew***@nowhere.uk> wrote in message
news:4642b13a.4070352@news.btopenworld.com...
> On Wed, 9 May 2007 18:29:13 -0500, "MP" <NoSpam@Thanks.Com> wrote:
>
> >Hi,
> >two part question
> >part1

> >so i thought of saving to ini file
> >
> >[SavedSearchesSection]
> >    Search0=FirstSearch
> >    Search1=SecondSearch
> >    etc
> >
> >question1
> >is that a normal way to setup incremental/indexed keynames? or am i using
> >ini in wrong way?
> >come to think of it, the search term itself could become the key and I
> >wouldn't need even a value!???

think I found the way to just retrieve entries under a section without
needing keys
use GetPrivateProfileSection and Split to create an array
i'd still have to find the way to store them that way(without key)...google
is my friend :-)
except with your following advice now i don't need ini at all!
:-)



>
> Either would be fine
> Your only decision is whether to use a standard INI file format or
> something of your own (call it CFG)

hmmm... hadn't thought of that....thought ini was the "cool" way <vbg> .. I
was all gettin ready to go out an buy some cheap sunglasses, get a tattoo
and pierce some body parts....damn


> - there are advantages in using your own format, one of which is
> having multiple fields with the same key name.

....sounds like TableName: FieldNames.... <g>
so you're meaning like I'd build a string
sTosave = "SectionName" & delim & Key & delim & Field1 & delim & val1 &
delim & Field2 & delim & Val2 & etc ???

I've always heard string concatenation was to be avoided in vb if
possible....course I could use Karl's cStringBuilder


>
> Personally I would not use the Win APIs for INI file management
>

well,originally I didn't want to reinvent the wheel, just learn how to
drive, but now you got my curiousity up...
didnt' know ini 's were 'to stay away from' ... so much for the
tattoos...<g>



> >it fits in with my desire to become more object oriented <g>
> >also fits with my recent contemplations of how to create a generic
Key/Data
> >storage class
>


> I would not use anything more complicated than needed

aww come on....I always have to do things the hardest way....<g>


> - initially keep all the data in a vbCrLf delineated String and write
> a few routines for inserting, getting, removing the data

you mean then store that to a std txt file as .cfg file you mentioned?
then read and write with std io functions ? and search with the instr/mid
combo

Show quoteHide quote
>
> It is just InStr Mid$ etc
>
> Eventually you'll probably wrap that in a Class, but mostly you'll
> just use it directly
>
> Storage, at its crudest are two Functions/Subs
>
>     Data$ = FileStr( FileName$ )
> and
>     Call StrFile( Data$, FileName$ )
>
> IMO one needs to work on the 'little' utilities that one will use all
> over the place
> - gradually, as needed, one writes wrappers around them, but really
> useful re-useable utilities tend to be pretty simple
>
> In short, Apps should be designed from top down, but generic utilities
> should be designed from the bottom up.
> - that way you get more re-useability


that does sound simple...ouch....i'm starting to think out of the
box...<vbg>

Thanks
Mark
Author
10 May 2007 7:21 AM
J French
On Thu, 10 May 2007 01:40:43 -0500, "MP" <NoSpam@Thanks.Com> wrote:

>Hi J
>Thanks for the response and sage advice.

>if I had a blackboard I would write this 10,000 times

>"I would not use anything more complicated than needed"

>maybe then I'd learn <g>

It is not a problem, you are just tackling things the wrong way round
- coming up with the 'house' before you have the 'bricks'

Just to digress about 1989 I realized that the most versatile and
fundamental thing in the BASIC language is the String
- it is really a little Object with very few properties, and is
something that can contain anything
- realistically it is one step up from raw memory, because it is a lot
easier to manipulate, duplicate and generally mess around with.

Strings are also extraordinarily efficient for data storage, with
named pairs if something is not there then nothing is stored.

If one is a bit careful, they can be human readable, which makes
debugging so much easier.

Just about anything can be reduced to a string containing what looks
like a single section of an INI file

You are on the right track
Author
10 May 2007 4:39 PM
Ralph
"J French" <erew***@nowhere.uk> wrote in message
news:4642b13a.4070352@news.btopenworld.com...
> On Wed, 9 May 2007 18:29:13 -0500, "MP" <NoSpam@Thanks.Com> wrote:
>
<snipped>
Show quoteHide quote
> >
> >question1
> >is that a normal way to setup incremental/indexed keynames? or am i using
> >ini in wrong way?
> >come to think of it, the search term itself could become the key and I
> >wouldn't need even a value!???
>
> Either would be fine
> Your only decision is whether to use a standard INI file format or
> something of your own (call it CFG)
> - there are advantages in using your own format, one of which is
> having multiple fields with the same key name.
>
> Personally I would not use the Win APIs for INI file management
>

In general I would agree, but one shouldn't forget other possible benefits.

Using an INI file format through the API guarantees a separate cache (for
lack of a better word) outside the File I/O of your application. IIRC Mr.
Butler posted a reply explaining how valuable this can be, especially for
error logging.

It also aids in managing collisions if multiple applications should be
accessing the same file.

Of course, if one doesn't need these services, one can cut to the quick and
roll their own.

-ralph
Author
11 May 2007 6:01 AM
J French
On Thu, 10 May 2007 11:39:05 -0500, "Ralph"
<nt_consultin***@yahoo.com> wrote:

Show quoteHide quote
>
>"J French" <erew***@nowhere.uk> wrote in message
>news:4642b13a.4070352@news.btopenworld.com...
>> On Wed, 9 May 2007 18:29:13 -0500, "MP" <NoSpam@Thanks.Com> wrote:
>>
><snipped>

>> Either would be fine
>> Your only decision is whether to use a standard INI file format or
>> something of your own (call it CFG)
>> - there are advantages in using your own format, one of which is
>> having multiple fields with the same key name.

>> Personally I would not use the Win APIs for INI file management

>In general I would agree, but one shouldn't forget other possible benefits.

>Using an INI file format through the API guarantees a separate cache (for
>lack of a better word) outside the File I/O of your application. IIRC Mr.
>Butler posted a reply explaining how valuable this can be, especially for
>error logging.

Yes, I spotted that post, it really made me raise an eyebrow
- potentially very interesting

>It also aids in managing collisions if multiple applications should be
>accessing the same file.

True

>Of course, if one doesn't need these services, one can cut to the quick and
>roll their own.

Yes
>-ralph

Under Win16 I once wrote a TSR that monitored file access, it was
alaming seeing the disk activity for even reputable Apps.
Author
11 May 2007 12:50 PM
Bob Butler
"J French" <erew***@nowhere.uk> wrote in message
news:464405d8.1391994@news.btopenworld.com...
> On Thu, 10 May 2007 11:39:05 -0500, "Ralph"
> <nt_consultin***@yahoo.com> wrote:
<cut>
>>Using an INI file format through the API guarantees a separate cache (for
>>lack of a better word) outside the File I/O of your application. IIRC Mr.
>>Butler posted a reply explaining how valuable this can be, especially for
>>error logging.
>
> Yes, I spotted that post, it really made me raise an eyebrow
> - potentially very interesting

I did? Don't remember that; not sure I'd ever use an INI for error
logging...
Author
11 May 2007 4:22 PM
Ralph
Show quote Hide quote
"Bob Butler" <noway@nospam.ever> wrote in message
news:%236wMrr8kHHA.3928@TK2MSFTNGP02.phx.gbl...
> "J French" <erew***@nowhere.uk> wrote in message
> news:464405d8.1391994@news.btopenworld.com...
> > On Thu, 10 May 2007 11:39:05 -0500, "Ralph"
> > <nt_consultin***@yahoo.com> wrote:
> <cut>
> >>Using an INI file format through the API guarantees a separate cache
(for
> >>lack of a better word) outside the File I/O of your application. IIRC
Mr.
> >>Butler posted a reply explaining how valuable this can be, especially
for
> >>error logging.
> >
> > Yes, I spotted that post, it really made me raise an eyebrow
> > - potentially very interesting
>
> I did? Don't remember that; not sure I'd ever use an INI for error
> logging...
>

Oops!

I think a google search is calling me. <g>

-ralph
Author
11 May 2007 5:00 PM
Ralph
Show quote Hide quote
"Bob Butler" <noway@nospam.ever> wrote in message
news:%236wMrr8kHHA.3928@TK2MSFTNGP02.phx.gbl...
> "J French" <erew***@nowhere.uk> wrote in message
> news:464405d8.1391994@news.btopenworld.com...
> > On Thu, 10 May 2007 11:39:05 -0500, "Ralph"
> > <nt_consultin***@yahoo.com> wrote:
> <cut>
> >>Using an INI file format through the API guarantees a separate cache
(for
> >>lack of a better word) outside the File I/O of your application. IIRC
Mr.
> >>Butler posted a reply explaining how valuable this can be, especially
for
> >>error logging.
> >
> > Yes, I spotted that post, it really made me raise an eyebrow
> > - potentially very interesting
>
> I did? Don't remember that; not sure I'd ever use an INI for error
> logging...
>

I'm sorry. Wrong "Bob".

http://groups.google.com/group/microsoft.public.vb.general.discussion/browse_thread/thread/5b29e1c1e68a1a36/aee7073429066524?lnk=st&q=&rnum=1&hl=en#aee7073429066524

I know I insulted one or both of you, but it wasn't done with malice. <g>

-ralph
Author
10 May 2007 6:59 AM
Steve Gerrard
"MP" <NoSpam@Thanks.Com> wrote in message
news:OqznbHpkHHA.1532@TK2MSFTNGP03.phx.gbl...

> I'd like to structure a class that I could reuse with very simple calls and
> not worry about re-implementing storage functions in every different app...
> If Not cStore.Exists(Key) Then cStore.Add(Key, Data) or something like that

While having an Exists method and an Add method are perfectly all right, you
could also add a method such as
    cStore.CheckAdd(Key, Data)
that would combine the two for you. That way you don't have to write that line
over and over.

Push the work into the class...
Author
10 May 2007 7:38 AM
MP
Show quote Hide quote
"Steve Gerrard" <mynameh***@comcast.net> wrote in message
news:zICdnaQbbsEuX9_bnZ2dnUVZ_tOmnZ2d@comcast.com...
>
> "MP" <NoSpam@Thanks.Com> wrote in message
> news:OqznbHpkHHA.1532@TK2MSFTNGP03.phx.gbl...
>
> > I'd like to structure a class that I could reuse with very simple calls
and
> > not worry about re-implementing storage functions in every different
app...
> > If Not cStore.Exists(Key) Then cStore.Add(Key, Data) or something like
that
>
> While having an Exists method and an Add method are perfectly all right,
you
> could also add a method such as
>     cStore.CheckAdd(Key, Data)
> that would combine the two for you. That way you don't have to write that
line
> over and over.
>
> Push the work into the class...
>

cool

I was just thinking that .Add would overwrite if it existed, so if you
didn't want that behaviour you'd check for exist.
so I guess I could use your suggestion when you don't want to overwrite and
..Add when you do,
'if for some reason you want to know if key already existed, could add a rtn
val
bAlreadyExists =  cStore.CheckAdd(Key, Data)'don't overwrite if exists
or
Call cStore.CheckAdd(Key, Data) 'if you don't care

bAlreadyExists =   cStore.Add(Key, Data) 'write or overwrite
or Call  cStore.Add(Key, Data)


or instead of two functions, add an optional boolean arg for bOverwrite
so
bAlreadyExists = Not cStore.Add (Key, Data, False) ' if key existed, and
bOver is false, call returns false so  bAlreadyExists = True
bAlreadyExists = Not cStore.Add (Key, Data, False) ' if key didn't exist,
write succeeds and returns true so  bAlreadyExists = False
(looks really ugly, eh?)

or
Call cStore.Add (Key, Data, True) 'write key if exists or not

could make optional default to whatever way you wanted.

just a thought

Thanks for the input
Mark
Author
10 May 2007 10:10 AM
J French
On Thu, 10 May 2007 02:38:06 -0500, "MP" <NoSpam@Thanks.Com> wrote:

..Default is a property you could consider
Author
11 May 2007 1:09 AM
Larry Serflaten
Show quote Hide quote
"MP" <NoSpam@Thanks.Com> wrote

> I was just thinking that .Add would overwrite if it existed, so if you
> didn't want that behaviour you'd check for exist.
> so I guess I could use your suggestion when you don't want to overwrite and
> .Add when you do,
> 'if for some reason you want to know if key already existed, could add a rtn
> val
> bAlreadyExists =  cStore.CheckAdd(Key, Data)'don't overwrite if exists
> or
> Call cStore.CheckAdd(Key, Data) 'if you don't care
>
> bAlreadyExists =   cStore.Add(Key, Data) 'write or overwrite
> or Call  cStore.Add(Key, Data)
>
>
>  or instead of two functions, add an optional boolean arg for bOverwrite
> so
>  bAlreadyExists = Not cStore.Add (Key, Data, False) ' if key existed, and
> bOver is false, call returns false so  bAlreadyExists = True
>  bAlreadyExists = Not cStore.Add (Key, Data, False) ' if key didn't exist,
> write succeeds and returns true so  bAlreadyExists = False
> (looks really ugly, eh?)
>
> or
> Call cStore.Add (Key, Data, True) 'write key if exists or not
>
> could make optional default to whatever way you wanted.
>
> just a thought


For another 2 cents....

You could create a simple list interface containing just two methods and a property.

Public Sub Load(Optional Source As String)
Public Sub Save(Optional Destination As String)

Public Property Get Item(ByVal Name As String) As Variant
Public Property Let Item(ByVal Name As String, ByVal Value As Variant)

Load and Save initialize and persist the data store, respectively, and Item
allows access to the list items.  The source and destination could be
filenames, or the source could be a connection string to a DB, or whatever
else you need it to be.

You don't need an Add method because simply assigning a value to a
new name would add it to the list.  And, you could use 'Nothing' as an
indicator to remove an item from the list:

Public Property Let Item(ByVal Name As String, ByVal Value As Variant)
  If IsObject(Value) Then
    If Value Is Nothing Then
      ' Remove object/value
    Else
      ' Add/Replace object
    End If
  Else
    ' Add/Replace value
  End If
End Property

The above might be used in an implementing class inteneded for 'generic'
use (allows either objects or values) but for more specific use you would
already decide if the item will be an object or a value.  For example, in an
implementing class that is designed to hold intrinsic values (Longs, Strings...):

Public Property Let Item(ByVal Name As String, ByVal Value As Variant)
    If VarType(Value) Or vbObject Or vbNull Then
      ' Remove value
    Else
      ' Add value
    End If
End Property

Here either assigning Nothing or Null would remove the item.

Assigning a value to a name would 'overwrite' the old value by default,
but your if your needs require a check first, that could be handled in the
implementing class.  The key here is that the interface is very small, and
it has the fundamental functions you need from a 'generic' list:

A method to indicate where the datastore is, and when to load it.
A method to indicate where the datastore should go, and when to save it.
And a means to create new items and recall them from the list.

Other more specific functions would be left to the implementing class
tailored to suit each application or need....

LFS
Author
11 May 2007 2:35 AM
MP
Show quote Hide quote
"Larry Serflaten" <serfla***@usinternet.com> wrote in message
news:%23UkM3j2kHHA.4900@TK2MSFTNGP05.phx.gbl...
>
> "MP" <NoSpam@Thanks.Com> wrote
>
> > I was just thinking that .Add would overwrite if it existed, so if you
> > didn't want that behaviour you'd check for exist.
> > so I guess I could use your suggestion when you don't want to overwrite
and
> > .Add when you do,
> > 'if for some reason you want to know if key already existed, could add a
rtn
> > val
> > bAlreadyExists =  cStore.CheckAdd(Key, Data)'don't overwrite if exists
> > or
> > Call cStore.CheckAdd(Key, Data) 'if you don't care
> >
> > bAlreadyExists =   cStore.Add(Key, Data) 'write or overwrite
> > or Call  cStore.Add(Key, Data)
> >
> >
> >  or instead of two functions, add an optional boolean arg for bOverwrite
> > so
> >  bAlreadyExists = Not cStore.Add (Key, Data, False) ' if key existed,
and
> > bOver is false, call returns false so  bAlreadyExists = True
> >  bAlreadyExists = Not cStore.Add (Key, Data, False) ' if key didn't
exist,
> > write succeeds and returns true so  bAlreadyExists = False
> > (looks really ugly, eh?)
> >
> > or
> > Call cStore.Add (Key, Data, True) 'write key if exists or not
> >
> > could make optional default to whatever way you wanted.
> >
> > just a thought
>
>
> For another 2 cents....
>
> You could create a simple list interface containing just two methods and a
property.
>
> Public Sub Load(Optional Source As String)
> Public Sub Save(Optional Destination As String)
>
> Public Property Get Item(ByVal Name As String) As Variant
> Public Property Let Item(ByVal Name As String, ByVal Value As Variant)
>
> Load and Save initialize and persist the data store, respectively, and
Item
> allows access to the list items.  The source and destination could be
> filenames, or the source could be a connection string to a DB, or whatever
> else you need it to be.

thats exactly what i've been thinking, just much clearer when you lay it out
like that

>
> You don't need an Add method because simply assigning a value to a
> new name would add it to the list.  And, you could use 'Nothing' as an
> indicator to remove an item from the list:

beautiful, so simple

Show quoteHide quote
>
> Public Property Let Item(ByVal Name As String, ByVal Value As Variant)
>   If IsObject(Value) Then
>     If Value Is Nothing Then
>       ' Remove object/value
>     Else
>       ' Add/Replace object
>     End If
>   Else
>     ' Add/Replace value
>   End If
> End Property
>
> The above might be used in an implementing class inteneded for 'generic'
> use (allows either objects or values) but for more specific use you would
> already decide if the item will be an object or a value.  For example, in
an
> implementing class that is designed to hold intrinsic values (Longs,
Strings...):
>
> Public Property Let Item(ByVal Name As String, ByVal Value As Variant)
>     If VarType(Value) Or vbObject Or vbNull Then
>       ' Remove value
>     Else
>       ' Add value
>     End If
> End Property
>
> Here either assigning Nothing or Null would remove the item.
>
> Assigning a value to a name would 'overwrite' the old value by default,
> but your if your needs require a check first, that could be handled in the
> implementing class.  The key here is that the interface is very small, and
> it has the fundamental functions you need from a 'generic' list:
>
> A method to indicate where the datastore is, and when to load it.
> A method to indicate where the datastore should go, and when to save it.
> And a means to create new items and recall them from the list.
>
> Other more specific functions would be left to the implementing class
> tailored to suit each application or need....
>
> LFS
>
>

I like it, sounds great, nice and simple
where do I mail the check for 2c?....and really you've got to adjust your
rates...look at the price of gas these days!!! <g>
:-)

I also like your previous idea of storing data in a string ( I think that
was your suggestion earlier) but haven't had time to think through exactly
how to implement it totally, using fields/keys/data/delims....using instr
for Exists and Mid for Item...neat idea, just everything takes me so long to
think through and get implemented and working,
sadly I'm not one of those genius types that just gets stuff instantly and
is running with it before the sentence is half finished...<g>

started working on it then got distracted by actual job...yuck...:-)

Thanks again for your valued contributions :-)

Mark
Author
11 May 2007 5:03 PM
MP
"MP" <NoSpam@Thanks.Com> wrote in message
news:uLSIZU3kHHA.208@TK2MSFTNGP05.phx.gbl...
>
> "Larry Serflaten" <serfla***@usinternet.com> wrote in message
> news:%23UkM3j2kHHA.4900@TK2MSFTNGP05.phx.gbl...
> >
> > "MP" <NoSpam@Thanks.Com> wrote
> >
>
> I also like your previous idea of storing data in a string ( I think that
> was your suggestion earlier)

oops, sorry it was J french