What Are You Actually Wanting To Measure ?
Without a doubt, the script that contains the following line within the second repeat loop:
set anItem to contents of anItem
will execute slower than the same script with that line removed (or commented out), and the reason for this is more-or-less as @wch1zpink described, but the other way around: with the above line included, every item being iterated over is being dereferenced (evaluated), and this takes time and slows things down. Conversely, when that line is commented out, everything in the repeat loop is being handled by reference, so no unnecessary evaluations occur, which is going to be substantially faster. It’s the entire reason AppleScript collections are held as referenced objects.
This is a similar principle to the speed enhancement observed when iterating over items in a list housed within a script object (it helps prevent needless dereferencing/evaluation of list items).
What Are Your Timings Actually Measuring ?
Clearly, what I’ve described is the complete opposite of what you’ve found to seemingly be the case in testing when timing these scripts. But this is where you have be very careful about what it is you’re actually timing, and in the case of these scripts, the vast majority of the apparent execution time is dedicated solely to the final line:
return newList
Replace this line in all of the scripts with something like:
return the length of the newList
Time the scripts again, and you’ll get a truer reflection of what I think you are actually trying to get a measure of.
@wch1zpink mentioned the processing of referenced items, which he believed was happening within the repeat loop and adding to the execution time. In fact, the processing is happening in the return
statement, and it’s purely in order to display the result for you. As @KniazidisR points out, if your list is still full of references, then printing these out will sometimes (but, by no means always) be more labour-intensive than either printing out a single reference to the entire collection, or printing out the fully-dereferenced list.
Fairer Testing
This wasn’t possible initially, as it was the differences in timings that you were questioning, so you wouldn’t have known where to focus your attention. But, in the end, the remit of these timed tests has been to compare the performance characteristics of dealing with list data when these data are handled by value versus by reference. This is achieved solely by the presence (by value) or absence (by reference) of this line:
set anItem to contents of anItem
Inadvertently, the final line:
return newList
added a separate, and additional, set of operations being timed, and these were different in one script compared to the other—that is, the seemingly identical return
statement in each script ends up having to do different things, and ends up affecting the outcome drastically.
With the benefit of hindsight, you can run a fairer test of speed, by ensuring—as far as conceivably possible—that the set of operations you wish to time represent the only functionally significant differences between the scripts, whilst aiming for the rest to be functionally equivalent (which will generally infer that the excess code will be similar, but it won’t always be identical).
I suggested earlier changing the last line of both scripts to:
return the length of the newList
But there’s no reason the scripts shouldn’t output the final list, provided either they both output a list of references (which is only possible for one script), or they both output the contents of the list. To do this, it’s sufficient to change the last line of the script handling items by reference, so that it dereferences the entire list—note that it this is usually the way you will want to approach things, because dereferencing all in one go will, again, be quicker than dereferencing item-by-item:
return the contents of the newList
The script that contains the line set anItem to contents of anItem
(uncommented) can keep its return
statement as is, since it has already dereferenced everything, or if you would prefer both scripts to use as much as the same code as possible, then it can also use return the contents of the newList
without impacting performance.
Results
[ AppleScript version:2.8
, system version:12.6.3
, CPU type:Intel x86-64h Haswell
, CPU speed:2300GHz
, physical memory:16384MB
]
Script A:
set anItem to contents of anItem
-
return newList
Execution time (approx.): 711ms
Script B:
set anItem to contents of anItem
-
return the contents of the newList
Execution time (approx.): 111ms