Previous Page
Next Page

22.3. List Access

When you access an attribute of a list, it is much faster to target a reference to the list, or the list as a script property, than to target the list directly. It's not entirely clear why this is; it seems like a bug. But it's a venerable and acknowledged bug, because even Apple's earliest documentation on AppleScript contains an example illustrating this point.

In this code (based on Apple's example) we total the numbers in a long list:

set L to {}
set total to 0
set bignum to 5000
repeat with i from 1 to bignum
    set end of L to i
end repeat
repeat with i from 1 to bignum
    set total to total + (item i of L)
end repeat
total -- 12502500, and it takes about 22 seconds to run on my machine

The big slowdown here is the second repeat block, accessing items of the list. If we access these items by way of a reference to the list, things speed up dramatically:

set L to {}
set refL to a reference to L
set total to 0
set bignum to 5000
repeat with i from 1 to bignum
    set end of L to i
end repeat
repeat with i from 1 to bignum
    set total to total + (item i of refL)
end repeat
total -- 12502500, and it took less than a second

Instead of a reference, you can get the same extraordinary speed bump by referring to the list as a script property:

set L to {}
set total to 0
set bignum to 5000
repeat with i from 1 to bignum
    set end of L to i
end repeat
repeat with i from 1 to bignum
    set total to total + (item i of my L)
end repeat
total -- 12502500, and it took less than a second

The magic word in that code is my. Take it away, and the code takes 22 seconds to run; with it, the code runs in less than a second. (Discovery of this remarkable device is generally credited to Serge Belleudy-d'Espinose.)

Now suppose all of that code is part of a handler, where L is a local variable. You can't take a reference to L, so you'd have to use the trick of making L a script property. To do so, you might have to create a script object expressly for this purpose; that may seem silly, but it's worth it:

on myHandler( )
    set L to {}
    script myScript
        property refL : L
    end script
    set total to 0
    set bignum to 5000
    repeat with i from 1 to bignum
        set end of L to i
    end repeat
    repeat with i from 1 to bignum
        set total to total + (item i of myScript's refL)
    end repeat
    return total
end myHandler
myHandler( ) -- 12502500, and it took less than a second

I've been unable to arrive at a rule explaining what causes list access to be slow and when it isn't. In the examples in this section, the first repeat block (containing set end of) is fast; it's the second repeat block that's slow. But this does not mean that set end of is always fast. Sometimes it's slow too, and I don't know why. However, all you need to know is that, in such cases, the tricks with reference-based or property-based access will speed it up. So these should be among the first weapons in your arsenal when you're looking for ways to optimize your code.


Previous Page
Next Page