Behaviour of Applescript lists

Hi everyone :slight_smile:
Could one of you Applescript geniuses here explain to me why this code does not return what I expected !

set listA to {"Apples", "Oranges", "Bananas"}
set listB to listA
copy "Pears" to the end of listB

I get listA AND listB equal to {“Apples”, “Oranges”, “Bananas”, “Pears”}

To get the result I would expect, I have to write :

set listA to {"Apples", "Oranges", "Bananas"}
set listB to {}
copy listA to the end of listB
copy "Pears" to the end of listB

If I do that, listA is still {“Apples”, “Oranges”, “Bananas”} and listB is {“Apples”, “Oranges”, “Bananas”, “Pears”}

I don’t understand this behaviour. Can someone please tell me what I’m missing.
Thanks in advance.

If I remember well, when you code set listB to listA you just give a second name to the original object.
When you code copy listA to listB you create a new object whose content is the same than the original one.

Searching in AppleScript User Guide, I retrieved:

Using the copy and set Commands
As its name implies, when you use the copy (page 153) command to create a variable, it always creates a separate copy (though note that a copy of an object specifier still specifies the same object). However, when you use the set (page 197) command to create a variable, the new variable always refers to the original object or value. You have essentially created another name for the same object.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) samedi 2 mai 2020 19:10:39

That’s exactly it ! All in a word :slight_smile: Thanks very much for the explanation.

The explanation is given. Here is the solution. Do not set listB to listA, but set listB to items (that is, contents) of listA. Because you need only contents of listA, and not whole listA object:


set listA to {"Apples", "Oranges", "Bananas"}
set listB to contents of listA
copy "Pears" to the end of listB

AppleScript items which can be “shared data” (as they’re sometimes called) are lists, records, and dates.

If you get a list’s ‘contents’ — or more correctly its ‘items’ — the result is a new list, but it contains exactly the same items. So you can make changes to one list at the list level without affecting the other list. But if any of their items are themselves lists, records, or dates, and you make changes in those items, the results will be visible in both lists. So:

set aList to {1, 2, {3, 4, 5}}
set anotherList to aList's items -- Another list containing the same items.
set item 1 of anotherList to 8 -- Replace existing item.
set item 3 of item 3 of anotherList to 7 -- Modify existing item.

return {aList:aList, anotherList:anotherList}
--> {aList:{1, 2, {3, 4, 7}}, anotherList:{8, 2, {3, 4, 7}}}

The ‘copy’ command, on the other hand, makes ‘deep’ copies of the stuctures being duplicated. Any lists, records, or dates within those structures are duplicated too:

set aList to {1, 2, {3, 4, 5}}
copy aList to anotherList -- Deep copy of the list structure.
set item 1 of anotherList to 8 -- Replace existing item.
set item 3 of item 3 of anotherList to 7 -- Modify existing item.

return {aList:aList, anotherList:anotherList}
--> {aList:{1, 2, {3, 4, 5}}, anotherList:{8, 2, {3, 4, 7}}}

I was informed years ago by one of Apple’s AppleScript engineers that ‘copy’ and ‘set’ do exactly the same thing when it comes to immutable objects such as numbers, strings, and enums. The results are the same objects, but because they can’t be modified, only replaced with other objects, it doesn’t make any difference. The reason ‘copy’ still takes slightly longer than ‘set’ in these cases is that its underlying code has to decide whether or not to duplicate the objects!

Hmm, now I’m starting to remember… Indeed, you need to use the copy command instead of set. Somewhere on this site, I myself have already described the difference between these commands. For some reason, the contents command stuck with me this time…

Although, I could achieve with contents command the same as Nigel Garvey in his last script. But still it is better to use the command copy. And here is an example of achieving the goal, if you forget (as me :)) that the command copy exists:


set aList to {1, 2, {3, 4, 5}}
set anotherList to contents of aList --create new reference to aList
set item 3 of anotherList to contents of item 3 of anotherList --create new reference to aList's item 3
set item 1 of anotherList to 8
set item 3 of item 3 of anotherList to 7

return {aList:aList, anotherList:anotherList}
--> {aList:{1, 2, {3, 4, 5}}, anotherList:{8, 2, {3, 4, 7}}}

NOTE: each creating new reference hold new place in the RAM for the new created object.

Thanks everyone :slight_smile:
I think “Copy” not “Set” sums it up pretty much in a nutshell :cool:

In real life, it just depends of what we want to do.

In your original message, you clearly wanted that listA remains unmoddified so copy listA to listB is the correct scheme.
But in a lot of scripts, we don’t need to retrieve the original list as it was so, set listB to listA is correct.
In fact, in such case I try to work without giving a new name to the list.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) dimanche 3 mai 2020 17:38:17

OK. You’re obviously a much more seasoned AppleScripter than me, the occasional scripter, but I’ve never come across an occasion where it could be useful to have two objects that are identical, but having different names. Sounds like a path to disaster to me.
Perhaps someday, I’ll see the light, but for now, I’m very happy with 1 object - 1 name !!