views:

43

answers:

1

Consider this code:

function Foo(ds as OtherDLL.BaseObj)
    dim lngRowIndex as long 
    dim lngColIndex as long

    for lngRowIndex = 1 to ubound(ds.Data, 2)
        for lngColIndex = 1 to ds.Columns.Count
            Debug.Print ds.Data(lngRowIndex, lngColIndex)
        next
    next
end function

OK, a little context. Parameter ds is of type OtherDLL.BaseObj which is defined in a referenced ActiveX DLL. ds.Data is a variant 2-dimensional array (one dimension carries the data, the other one carries the column index. ds.Columns is a Collection of columns in 'ds.Data`.

Assuming there are at least 400 rows of data and 25 columns, this code takes about 15 seconds to run on my machine. Kind of unbelievable.

However if I copy the variant array to a local variable, so:

function Foo(ds as OtherDLL.BaseObj)
    dim lngRowIndex as long 
    dim lngColIndex as long
    dim v as variant

    v = ds.Data
    for lngRowIndex = 1 to ubound(v, 2)
        for lngColIndex = 1 to ds.Columns.Count
            Debug.Print v(lngRowIndex, lngColIndex)
        next
    next
end function

the entire thing processes in barely any noticeable time (basically close to 0).

Why?

+2  A: 

Chances are that ds.Data is creating/copying the entire array each time it is accessed (e.g. by fetching it from a database or something), and this is taking a significant amount of time.

By accessing it inside the loop you are then doing this copy operation hundreds of times. In the second case, you copy it once into a local variable outside the loop, and then quickly re-use that data hundreds of times without having to actually copy it again.

This is a common and very important optimisation technique: move any unnecessary work out of the loop so it's executed as few times as possible. It's just that in your example, it's not "obvious" that it's doing lots of extra work when you access Data.

Jason Williams
Note to remember: property 'getters' can perform computations (or even have side-effects)
pst
@Jason Williams. That was the first thing I checked. The getter is NOT fetching anything from anywhere. Everything is in memory. The getter has a private variable counterpart which is basically a 2-dimensional array. That is what it returns.
AngryHacker
If the getter is a Property that returns an array, it will cause the entire array to be copied every time the property is accessed. Change it to a GetData() method that returns the array and this copying will be avoided.
Jason Williams
@Jason, yeah, that's probably what it is, because it's on the stack.
AngryHacker