Why do these even exist? It seems absurd. Like with most dynamic languages, AppleScript types seem to be either immutable primitive types like integer
s and real
s which are going to be handed around by value and don't make any sense to use with a reference to
, or object-like types like application
s, script
s, or record
s, which are being passed around by reference already. How is a reference to
not completely redundant? Here's an example taken from Apple's AppleScript Language Guide (https://developer.apple.com/library/archive/documentation/AppleScript/Conceptual/AppleScr开发者_C百科iptLangGuide/introduction/ASLR_intro.html):
tell app "Finder" to set diskRef to a ref to startup disk
--result: startup disk of application "Finder"
So do you mean to tell me that if I did this instead,
tell app "Finder" to set diskObj to startup disk
--result: startup disk of application "Finder"
that the applescript runtime is going to send an apple event sent across to the Finder process telling it, "hey - some guy just asked you to return an octet stream of /dev/disks01 back to me! Haha! I guess he should have asked for a reference to
it! Let's get started! This is going to take a while!"
I'm programming in Python and I do this:
m = fileHandle.read( 1000000000 ) #and then wait a little while
n = m
Did I just copy a gig of data around in memory? Of course not. But the existence of a reference to
in AppleScript implies that assigning objects to new variables is a by-value operation. And if that's the case, what's the deal with the copy
command?
What's going on here?
UPDATE: Well, just consider me a confused Python programmer. Just to make this a bit more clear, I still think
tell app "Finder" to set diskRef to a ref to startup disk
--result: startup disk of application "Finder"
is a poor example (taken from the applescript language guide). But @Chuck's example of a reference to
the property itself holding a primitive type that can then be reassigned is a better one. IOW, a reference
object is really a variable/property that holds a pointer to another variable or property.
My understanding is that you can think of references as pointers.
set x = 5
set y to reference to x
set contents of y to 10
log x -- 10
In general, you don't manually create references. AppleScript libraries and dictionaries may return them, but then you work with the properties of the returned item (name of startup disk
for example).
Honestly, I'd ignore them. In twenty years of working with AppleScript, I've probably had to look up the documentation to references once. If you're trying to do something in AppleScript and believe you need to create a reference variable, you're probably not doing it in the most straightforward manner.
Check out this MacTech article for a more detailed discussion of AppleScript references.
Two variables in AppleScript, like in Python, can share the same value. Each variable has a reference to its value, but the word "reference" has other meanings. The string "https://stackoverflow.com/"
is a reference to a web site; the integer 42
is a reference to the works of Douglas Adams; and an object of class reference
in AppleScript is a different kind of reference.
An object of class reference
postpones access to an element or property of some object. It's almost like a lambda in Python, because the AppleScript
set v to {11, 22, 33}
set r to a reference to item 2 of v
acts like the Python
v = [11, 22, 33]
r = lambda: v[1]
by postponing access to the 2nd item of a list. Then contents of r
in AppleScript or r()
in Python would get the item. AppleScript can also set the item with set contents of r to 99
; Python can't set the item with this lambda. Python's lambdas can do many things that AppleScript's references can't do.
a reference to
operator
The AppleScript Language Guide describes the a reference to
operator but misses some important details. The operator has one operand; the compiler also accepts reference OPERAND
or ref OPERAND
, then rewrites them as a reference to OPERAND
.
If the operand is an expression of the form A of B
or B's A
, then the operator wraps the expression in an object of class reference
. This expression can be an element, like item 2 of q
, or a property, like length of q
.
If the operand is a variable, then the operator attaches an implicit my
or of me
. For example, a reference to q
in the run handler is the same as a reference to my q
. This becomes confusing in scopes where q
and my q
are different.
For other operands, then the operator only returns the operand. For example, a reference to 3
returns 3, which is not an object of class of reference
.
The operator captures the current value of variables. For example, a reference to item i of q
captures the values of i and q. For contrast, a reference to q
doesn't capture the value of q, because it is the same as a reference to my q
, so it sees q as a property, not a variable.
to demo()
set q to {11, 22, 33}
set rq to a reference to q
set i to 2
set ri to a reference to item i of q
set i to 3
set item 2 of q to 55
set q to {77, 88, 99}
{contents of rq, contents of ri}
end demo
set q to "a string"
demo()
The result of this script is {"a string", 55}. Reference rq ignored the local q and used my q
from the run handler. Reference ri captured the local values of i and q, ignored later assignments to i and q, but didn't ignore the assignment to item 2 of q.
Using references with big lists
The AppleScript Language Guide also has examples using the a reference to
operator to increase the speed of accesses to a big list. The Guide uses
set bigListRef to a reference to bigList
but fails to explain that the reference is implicitly a reference to my bigList
, so the access is through the script object me
. It only works because the code is in the run handler, where bigList
and my bigList
are the same list.
It turns out that accesses to a big list are fast if the reference goes through any script object. Other accesses are slow. The next script shows this by creating a list of 7000 items using fast accesses, and then reading the list using both slow and fast accesses.
to bench(what)
set start to current date
repeat with i from 1 to 7000
if item i of what is not 42 then
error "wrong value"
end if
end repeat
(current date) - start
end bench
to bench2()
script box
property nums : {}
end script
repeat 7000 times
set end of box's nums to 42
end repeat
{bench(box's nums), bench(a reference to box's nums)}
end bench2
bench2()
I ran this script on my old machine running PowerPC Mac OS X 10.4.11. The result was {19, 0}, so the slow accesses took 19 seconds, and the fast accesses took 0 seconds.
The line set end of box's nums to 42
does a fast access without using the a reference to
operator. It is fast because the access goes through box
, a script object.
精彩评论