VBA-Better-Array icon indicating copy to clipboard operation
VBA-Better-Array copied to clipboard

Add iterable support

Open b-gonzalez opened this issue 2 years ago • 5 comments

Has there been any thought to adding iterable support for Better Array? You can do that by adding a NewEnum property like so:

Public Property Get NewEnum() As IUnknown
Attribute NewEnum.VB_UserMemId = -4
    Dim it() As Variant
    Static pCol As Collection
    Dim elem As Variant
    
    Set pCol = New Collection
    
    it = Items
    
    For Each elem In it
        pCol.Add elem
    Next elem
    
    Set NewEnum = pCol.[_NewEnum]

End Property

If you did that, you could iterate through a BetterArray object. So you could write code like so:

Option Explicit

Sub subby()
    Dim ba As New BetterArray
    Dim elem As Variant
    
    ba.Push 1,2,3
    
    For Each elem In ba
        Debug.Print elem
    Next elem
End Sub

With this approach, you don't have to call the items property directly to do iteration.

b-gonzalez avatar Jan 15 '23 18:01 b-gonzalez

Been a while since I looked at this so this comment isn't meant to close this discussion necessarily. Just explain some of what I remember - some of which may be wrong.

As far as I can remember:

VBA SAFEARRAYS do actually already support enumeration. So for example, your example code would work without any changes to BetterArray if modified to specify the Items property:

Sub Subby()
    Dim ba As New BetterArray
    Dim elem As Variant
    
    ba.Push 1, 2, 3
    
    For Each elem In ba.Items
        Debug.Print elem
    Next elem
End Sub

So, really this enhancement is not so much about adding support for the NewEnum attribute, but changing the default property of the class. I think that if Items were the default property (e.g carried the attribute Item.VB_UserMemId = 0) then your code would work, right?

Problem is, of course, you can only have one default property regardless of context. At the moment Item is the default property, not Items, so you can access an index like ba(x) = 1 in addition to ba.Item(x) = 1.

Senipah avatar Jan 16 '23 10:01 Senipah

From what I can tell, I don't think changing items to the default member will be sufficient. I understand where you're coming from however. If you can iterate by explicitly calling items, then implicitly calling it, e.g. by setting it as the default member, should also work. I tried experimenting with that but it just resulted in errors however.

To create an iterable that can be used in a for each loop in an object, you have to assign VB_UserMemId to the value of -4. A value of 0 sets the procedure as the default member. A value of -4 marks the procedure to be used when iteration occurs (e.g. when used in a for each loop). The procedure that's typically given this attribute is the NewEnum procedure. In this procedure you also need to use a data structure that implements NewEnum (like the collection) and reference that under the hood. That data structure must also preserve its contents through the for each calls. So it needs to be declared as static, private, etc.

So my update just prevents you from needing to calls the items property explicitly. That may not seem like a big deal and I agree that it isn't. But it puts BetterArray more inline with how other data structures in VBA and other languages work with iteration.

b-gonzalez avatar Jan 16 '23 16:01 b-gonzalez

Roger. I'll take a look.

I have a feeling it won't be possible, though, because if memory serves you can only implement NewEnum on custom collection classes.

BetterArray uses VBA Arrays internally - this was an explicit design choice to benefit from some of the performance benefits arrays have over collection objects and transferring everything into a collection probably negates any of that. Additionally, it would be such a significant change to make it use collections instead that it would effectively constitute a rewrite from the ground up. Given the number of classes floating around on Github and online that are effectively wrappers around collections I don't think I would be adding anything new to that space.

Senipah avatar Jan 16 '23 18:01 Senipah

Just going to leave this link here to refer back to when I have time to look at this in some detail.

https://www.vbforums.com/showthread.php?883687-RESOLVED-Is-it-possible-to-add-an-enumerator-to-an-array

Senipah avatar Jan 16 '23 18:01 Senipah

I was trying to delete some of the edits on my previous comment but it looks like GitHub deleted the original as well. But you should have versions of my comment in an email. So you should be able to use that if desired.

b-gonzalez avatar Jan 17 '23 15:01 b-gonzalez