22.3. List AccessWhen 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. |