TIL: Subexpressions may use a different scope

I am in the middle of adding AppleScript support to another one of my apps (this time: Find Any File), and I run into a weird error while testing basic functions.

This works:

set firstWin to first window
set theWin to windows where its document is (document of firstWin)

But this doesn’t:

set theWin to windows where its document is (document of first window)

Error message: “Can’t get window 1 of window”

Why is that, and is that normal? Did I just write it wrong?

Ah, actually, this works:

set theWin to windows where its document is (document of my first window)

So, it’s that the selector runs in a different context, where “window” isn’t know, it appears.

I’ll leave this resolved question here as a “good to know”.

Also, you can run:

set theWin to windows where its document is (a reference to document of window 1)
1 Like

Huh, I never understood the use cases for “reference to”, and your example only adds to my confusion :slight_smile:

This is a pointer (large HEX address) to the 1st byte of the object in RAM memory. A pointer is a synonym for an object, as them “understand” the machine. And you just needed to compare documents (objects).

Ah, you mean that this speeds up the lookup because without reference to it would compare the entire object’s properties by default?

Also, can you explain why this isn’t working the same way?

set theWin to windows whose document …

So, instead of where its, why can’t I use whose?

Especially, because if I enable “Replies” in Script Editor, it lists the event as:

get every window whose document = document of window 1

So it internally uses whose there. Weird.

Hi.

The value returned by a reference to is an AppleScript specifier, which you’d normally keep in a variable for later use.

For instance, if you set a variable to an application’s front window, it’s very likely that the application will return a specifier referring to the ID of its frontmost window at the time. This is the value that will be stored in the variable and the window with that ID will be the one referred to when you use the variable, even if it’s no longer the frontmost window when the variable’s used. If you want the variable always to refer the whichever window’s frontmost when you use the variable, you set it to a reference to the application’s front window. This way, it’s a window 1 specifier that’s stored, not a window id blah one.

a reference to can also be used to get a specifier for an object that doesn’t exist at the time the variable’s set:

set myList to {}
set item17 to a reference to myList's item 17 --> item 17 of {}

repeat with i from 1 to 20
	set end of myList to i
end repeat

return item17's contents
--> 17

These are the official uses for a reference to, although it’s more well known in some quarters for it’s ability to speed up access to items in very long lists. :slight_smile:

3 Likes

Ah, yes, that makes sense. I ran into troubles like that in my first scriptable app (iClip) years ago and I solved it by giving every object its own unique id, even the elements of an array (list). Because without that, doing a repeat loop over an array while also changing the array in the loop would mess things up. By using ids I solved that. But with arrays, I guess that problem remains, right, because I cannot loop over the references of an array, or can i?

This also relates to solving this question, probably: How to get "id" working for scriptable objects? - For Developers - Late Night Software Ltd.

That’s right, if it’s explained in AppleScript.

AppleScipt is a language that by concept of a reference hides from the user the concept of an address (pointer), which is basic to the processor and low-level languages. On the one hand, this simplifies the task for user, on the other hand, it lowers the level of understanding of how it all works. Those who started by writing a stream of binary bytes and launching this stream from a tape recorder will understand me.

What is myList for a machine? This is the address of the 1st byte of the object in RAM. And what is item 17 for it? This is the address of the byte = the address of the 1st byte+17. That is, 17 is the offset of the address of this byte relative to the address of the list object address. For an empty list, the contents in that memory location do not yet belong to the list, but the location itself exists. Therefore, AppleScript allows this offset address to be remembered as a legitimate one.

Yes. It will compare 2 addresses (which is large integers) instead of comparing contents of 2 objects.

1 Like

What about this?

set theWin to windows where its document is (get document of first window)

Sometimes that explicit get is required…

1 Like

Variables and positions in lists are indeed really pointers to memory addresses. These addresses used to be (and probably still are) pointers to other pointers which are maintained by macOS’s memory management system and which redirect to where the required items are actually currently stored in the computer’s memory.

Besides data belonging to AppleScript itself — such as text, numbers, lists, records, and date objects — items “contained” by variables can be specifiers (or references), which are ways of describing objects rather than pointing to where they are in memory. Importantly in AppleScript, they’re ways of telling scriptable applications, scripting additions, and the like what information’s required from them. AppleScript doesn’t have direct access to an application’s objects or values. It has to pass appropriate specifiers to the application and the application itself then fetches the required information from its own internal workings and returns it to the script. Depending on what’s required, a returned result will either be AppleScript value, another specifier belonging to the application, or a hybrid of both — ie. a list or record containing one or more specifiers. Every time a specifier belonging to an application is used, it’s the application which does the work. Depending on how the application’s been written, it may be necessary to pass complex specifiers in stages, as Chris does above.

I just wanted to say that no matter how AppleScript hides the essence of the script from the user, it’s still the same good old stream of 0 and 1 with branching points.

Example of a loop over the references:

set alist to {"H", "e", "l", "l", "o", ", ", {"Alex", "Jon", "Sam"}}

set newList to {}
repeat with anItem in item 7 of alist
	set aText to ""
	repeat with bItem in items 1 thru 6 of alist
		set aText to aText & contents of bItem -- can remove "contens of" because left operand is string
	end repeat
	set end of newList to aText & contents of anItem & " !" -- can remove "contens of" because left operand is string
end repeat

newList --> {"Hello, Alex !", "Hello, Jon !", "Hello, Sam !"}
1 Like