We've had several users request that we deprecate the Collection class since it's ancient, and trivial to implement yourself. It's not exactly high on my list of things to deprecate because it works, and doesn't have a very high maintenance burden. But, it would be a very interesting test case for a deprecation strategy I've had. My idea has been to take some of the simpler functionality that we deprecate and replace it with example projects. When it comes time to remove the deprecated feature, we could have a process automatically add the example project to your existing project. Voila! Instant migration strategy that involves very little pain on the user's part. You can continue to use the Foobar class, since it's part of your project. And we can officially stop supporting it since you would then have the source code to it.
Now, the process whereby we determine a user is making use of the Collection class is an interesting one, and best left for another time. The thing that I found very cute about this little idea came about when I rewrote the Collection class.
In our C++ code, the collection class is about 270 lines of C++ code when you include all of the declarations, comments, etc. Not huge, by any means. When I rewrote it in REALbasic, it was a whopping 47 lines, 35 of which are comments and declarations! The collection class is an excellent example of when to use Pairs. It essentially wraps an array of pairs, where Pair.Left is the key, and Pair.Right is the value. As you can imagine, writing the class is pretty easy. The add method just Appends a new pair into an array. The remove and lookup methods that use an index just index into the array. The remove and add methods which use a key loop over the array and look at the element's .Left value to match against the key. That's it. Nothing more!
Kind of neat, and so I'm attaching the entire source code for the Collection class here so you can see why Pairs are a handy construct to have built into the framework.
Class Collection
Function Item(index as Integer) As Variant
// Indexes are one-based for historical reasons, so we need to
// subtract one since our arrays are zero-based.
//
// We don't have to do any error checking -- the out of bounds
// exception is on the user to deal with.
return mItems( index - 1 ).Right
End Function
Function Item(key as String) As Variant
// See if we can locate the value by key. If we
// can, then return the value. If we can't, then
// we just return nil.
for i as Integer = 0 to UBound( mItems )
if mItems( i ).Left = key then return mItems( i ).Right
next i
return nil
End Function
Sub Add(value as Variant, key as String = "")
mItems.Append( key : value )
End Sub
Sub Remove(index as Integer)
// Indexes are one-based for historical reasons, so we need to
// subtract one since our arrays are zero-based.
//
// We don't have to do any error checking -- the out of bounds
// exception is on the user to deal with.
mItems.Remove( index - 1 )
End Sub
Sub Remove(key as String)
// See if we can find the item to remove by key. Note that
// for historical reasons, we only delete the first element that
// we find with a matching key.
for i as Integer = 0 to UBound( mItems )
if mItems( i ).Left = key then
mItems.Remove( i )
return
end if
next i
End Sub
Property Count As Integer
Get
return UBound( mItems ) + 1
End Get
End Property
Private mItems() As Pair
End Class
As for whether Collection will be deprecated or not: I really don't know. There's not been enough research done to determine whether it would justify doing it. For instance, if there were plugins using Collection, then those might break depending on how they were written. My gut tells me that it won't be deprecated because there's no cost to maintaining it, but some risk in deprecating it, to be entirely honest.
What's interesting here was the fact that Collection was so trivial to rewrite -- back when Collection was added to the framework, it would have been very inefficient to implement in pure RB code (if not impossible -- I don't think you could implement optional parameters in v2 when Collection was first exposed). Now it's blindingly simple to do!
Aaron wrote: "...we could have a process automatically add the example project to your existing project."
I don't understand what you mean here.
@Russ -- I mean that a new class would be added to your project automatically to take the place of the deprecated functionality. So in this case, Collection would be gone from the framework, and instead, you'd have an RB class in your project named Collection.
I'm a huge fan of rewriting more and more of the framework in RB itself, so in that respect alone this is great to see! Nice use of Pairs as well...
I've wondered why the Pair class was added to the language at a time when RB was seemingly in the process of simplifying the language. The Pairs class seems like an excellent case of a class that would be trivial for the user to implement him/her self. My impression is that it was useful to RB in eating their own dog food, as it were, and that it could not hurt to expose the functionality to the user. The above reinforces that impression in my mind. (Rightly? Wrongly?)
On another note, when new functionality like Pairs is announced, the first thing RB fans such as myself are going to do is look it up in the Language Reference of the new release. If it makes the press release, it should be in the documentation (I think), heh. I suppose that the pair class is simple enough that the syntax completion capability of the IDE is enough to work with. Aaron's blog is always superb, and shortly after the R2 release an entry appeared here regarding the Pair class. (Thank you.) However RB users should not have to resort to a blog to get basic documentation of the language.
@SnappyFish -- Pairs would be an easy class for the user to implement themselves, except for the compiler support that they allow for. For instance, the user would never be able to implement the colon operator for creating pairs. And, as with any new functionality, you should keep in mind that the benefit might not be immediately apparent since we tend to introduce functionality in steps. As for the documentation; that was a simple mistake and not indicative of the way things normally are.
While I like the simplicity of this approach using Pair, I'm a bit worried about its performance. I believe that the Key() function is rather highly used in a Collection class, and currently its implementation does a linear search over all items.
I wonder if this wouldn't be much faster by using two separate, parallel, arrays for keys and values, so that the key lookup could be done with IndexOf, which I assume is faster than a RB-coded search loop, wouldn't it?
@Thomas -- The RB Collection class I posted is identical to the C++ Collection class that was implemented. Yes, you could use parallel arrays to implement it if you want. You could use a Dictionary. You could use all sorts of things.
FWIW, as far as I'm concerned the only purpose I ever had for the collection class was as a way to store an array of items in a Dictionary. Since you guys added the ability to assign standard Arrays to a Variant, I no longer have any need for it.
I am however curious about how the performance of the RB-coded Collection class compares to that of the original C++ version. It seems like something that would get noticeably slower using RB's non-optimising compiler (at least unless you were to liberally apply the backgroundtasks false and boundschecking false #pragmas).