Why does the set item command do this?

I thought I more or less understood Applescript but I have never noticed this before. Hope I’m not being really thick here.

Why/how does the first routine, with the set item command, change the original variables but the second routine does not? What is the linkage?

I need to be able to save a list, access non contiguous values in the list and then retrieve the original list. So far, I can’t do this. The (I thought) saved list is overwritten.

Thanks for the help.



set thisList to {1, 2, 3}
set saveThisList to thisList
set ret to test(thisList)
--set ret to test2(thisList)
return thisList # RESULT: {0,0,0}
-- return saveThisList # SAME RESULT: {0,0,0}

# THIS DESTROYS THE ORIGINAL LIST:
on test(theInput)
	repeat with k from 1 to 3
		set item k of theInput to 0
	end repeat
	return "whatever"
end test


# BUT THIS DOESN'T:
on test2(theInput)
	repeat with eachItem in theInput
		set eachItem to 0
	end repeat
	return "whatever"
end test2


Model: MacBook Pro
AppleScript: 2.7
Browser: Safari 605.1.15
Operating System: macOS 10.14

Hi LouK.

The value of the variable ‘eachItem’ in the second handler is a reference to an item in the list. When you set eachItem to 0, you’re setting the value of the variable, not of the item. To change the item’s value, you need to use the ‘contents’ property:

on test2(theInput)
	repeat with eachItem in theInput
		set contents of eachItem to 0 -- or: set eachItem's contents to 0
	end repeat
	return "whatever"
end test2

Thanks for the reply. The second routine works without the contents attribute as well.

But my issue is in the first routine, how to access random positions in a list without overwriting the original list. I have found a workaround, but it seems tedious, rebuild the list. Seems it should be simpler.



set thisList to {1, 2, 3}
set ret to test(thisList)
return thisList

on test(theInput)
	set theInput to saveList(theInput)
	repeat with k from 1 to 3
		set item k of theInput to 0
	end repeat
	return "whatever"
end test

on saveList(x) # prevents routine from overwriting original lists
	set xA to {}
	repeat with eachItem in x
		set xA to xA & eachItem
	end repeat
	return xA
end saveList


I mean if I say set saveList to thisList, which I do to save the original, it overwrites saveList as well. It’s like they take on the same identity. Seems weird to me.

LouK. I believe there are two issues involved. The first is the one Nigel makes note of regarding the use of the “contents of” property. The second concerns the operation of the set and copy commands, which are discussed in the AppleScript Language Guide:

So, script one works as expected:

set thisList to {1, 2, 3}
copy thisList to saveThisList
set ret to test(thisList)
thisList --> {0,0,0}
saveThisList --> {1, 2, 3}

on test(theInput)
	repeat with k from 1 to 3
		set item k of theInput to 0
	end repeat
	return "whatever"
end test

And, script two with the “contents of” property also works as expected:

set thisList to {1, 2, 3}
copy thisList to saveThisList
set ret to test(thisList)
thisList --> {0,0,0}
saveThisList --> {1, 2, 3}

on test(theInput)
	repeat with eachItem in theInput
		set contents of eachItem to 0
	end repeat
	return "whatever"
end test

Lastly, this script demonstrates the need for the “contents of” property.

set thisList to {1, 2, 3}
copy thisList to saveThisList
set ret to test(thisList)
thisList --> {1, 2, 3}
saveThisList --> {1, 2, 3}

on test(theInput)
	repeat with eachItem in theInput
		set eachItem to 0
	end repeat
	return "whatever"
end test

BTW, you state that you want to “access non contiguous values in the list”, but I don’t think that’s what your scripts do. Perhaps I don’t understand what you are trying to accomplish.

In AppleScript, when passing an object reference parameter (list, here) to the handler, this parameter is passed as a global variable. So to save the original list, you need to create a local copy (variable) of it:


set thisList to {1, 2, 3}
set ret to test(thisList) --> {0,0,0}
return thisList --> {1,2,3}

# THIS DOESN'T DESTROY THE ORIGINAL LIST:
on test(theInput)
	copy theInput to theInput -- THIS makes theInput LOCAL VARIABLE
	repeat with k from 1 to 3
		set item k of theInput to 0
	end repeat
	return theInput -- returns local list
end test

OR, instead of passing a reference to the list, pass to the handler its contents:


set thisList to {1, 2, 3}
set ret to test(contents of thisList) --> {0,0,0}
return thisList --> {1,2,3}

# THIS DOESN'T DESTROY THE ORIGINAL LIST:
on test(theInput)
	repeat with k from 1 to 3
		set item k of theInput to 0
	end repeat
	return theInput
end test