Does anyone know why this applescript works? I do not understand why. The script generates three dialog boxes containing the same message: "Hi There". I have two questions:
1) How can j and k be set to reference i before i is defined?
2) Why does not r reference the i defined in test2?
on test1()
return get a reference to i
end test
on run
set j to test1()
set k to a reference to i
set i to "Hi there"
display dialog j
display dialog k
test2()
end run
on test2()
set i to "now see here"
set r to a reference to i
display dialog r
end test2
Note: The Script Editor is Version 2.7 and the AppleScript Version is 2.4.
I feel foo answered my second question on Nov 18. As for the first question, I will offer my own explanation, which I discerned after reading about Object Specifiers. The following statement, taken from my example, contains an implicit of (get me)
.
return get a reference to i
To illustrate, I will rewrite the statement explicitly.
return get a reference to i of (get me)
When either of these statements execute, a reference object is created which contains an object specifier. The phrase between the a reference to
and the get
is not evaluated, instead it is stored in the object specifier. In this case, the phrase is i of
. What is to the right of the get
is evaluated and this result is also stored in the object specifier. In this case, this result is me
which is the top-level script object. This is why the variable i
does not have to exist, when the reference object is returned from the test1
handler. When the display dialog j
statement executes, the reference object is fully evaluated. It is at this point the variable i
must exist. This same explanation can be applied to the variable k
shown in my example.
I do realize that a text phrase, to be evaluated later, probably is not actually stored in an object specifier. At the very least, I know the phrase is parsed and syntax checked, but the AppleScript Language Guide does not definitely state how the unevaluated part of a statement is stored.
To me, the placement of the implicit get
seems to be somewhat arbitrary. Let me illustrate my point with some examples. (Here for brevity, I have omitted proofs. If reader(s) can not verify, let me know and I will include proofs)
Example 1: If you write
set r to a reference to i
you get
set r to get a reference to i of (get me)
Example 2: If you write
set r to a reference to item 2 of i
you get
set r to get a reference to item 2 of (get i of me)
Example 3: If you write
set r to a reference to i of me
you get
set r to get a reference to i of (get me) -- same as Example 1
Example 4: If you write
set r to a reference to item 2 of i of me
you get
set r to get a reference to item 2 of i of (get me) -- differs from Example 2
If you wish to set the contents of a reference to a object, I found the following restriction. The number of in
and of
reserved keywords in a phrase, contained by a object specifier, must equal unity. A total of zero or more than one will result in a script execution error. The example below illustrates this.
property j : {1, 2, {3, 4}, {{5, {6, 7}}, 8, 9}}
log "Line 1: " & j
set r to a reference to item 3 of j -- phrase is "item 3 of", object is (get j of me)
set contents of r to "aa" -- Succeeds since total count is 1
log "Line 2: " & j
set r to a reference to item 2 of (get item 1 of item 4 of j) -- phrase is "item 2 of", object is (get item 1 of item 4 of (get j of me))
set contents of r to "bb" -- Succeeds since total count is 1
log "Line 3: " & j
set j to {1, 2, {3, 4}, {{5, {6, 7}}, 8, 9}}
log "Line 4: " & j
set r to a reference to item 3 of j of me -- phrase is "item 3 of j of", object is (get me)
try
set contents of r to "cc" -- Fails since total count is 2
on error msg
log "Line 5: " & msg
end try
log "Line 6: " & j
set r to a reference to item 2 of item 1 of item 4 of j -- phrase is "item 2 of item 1 of item 4 of", object is (get j of me)
try
set contents of r to "dd" -- Fails since total count is 3
on error msg
log "Line 7: " & msg
end try
log "Line 8: " & j
The log output is given below.
(*Line 1: 123456789*)
(*Line 2: 12aa56789*)
(*Line 3: 12aa5bb89*)
(*Line 4: 123456789*)
(*Line 5: Can’t set item 3 of j to "cc".*)
(*Line 6: 123456789*)
(*Line 7: Can’t set item 2 of item 1 of item 4 of {1, 2, {3, 4}, {{5, {6, 7}}, 8, 9}} to "dd".*)
(*Line 8: 123456789*)
The statement set contents of r to "bb”
worked because I added an explicit get
to the previous statement. This forced early evaluation of part of the object specifier.
Next, I would like to address the question “What is the context you feel like you need to [use references]?” asked by tweaks on Nov 17.
Originally, I was trying to find a way for a handler to return two values through passed parameters. A working example is shown below.
set r to missing value
set s to missing value
FirstAndLast(a reference to r, a reference to s, "now is the time for all good men")
log r
log s
on FirstAndLast(alpha as reference, omega as reference, message as text)
set contents of alpha to first word of message
set contents of omega to last word of message
end FirstAndLast
Executing this code produces the log output:
(*now*)
(*men*)
The code, shown above, has two drawbacks: 1) The variables r
and s
can not be local. 2) The variables r
and s
have to exist before the handler FirstAndLast
is called. After working with Applescript for a while, I realize there are better ways to implement this code. One way is to employ pattern assignment as described in the AppleScript Language Guide. The code using pattern assignment is shown below.
set {r, s} to FirstAndLast("now is the time for all good men")
log r
log s
on FirstAndLast(message as text)
set alpha to first word of message
set omega to last word of message
return {alpha, omega}
end FirstAndLast
This version has three advantages. 1) Here no reference objects are used. 2) The identifiers r
and s
can represent local variables, global variables or properties. 3) If the identifiers r
and s
represent variables, the variables do not have to exist before calling the handler FirstAndLast
.
Finally, evidently handlers are objects. If you think I am wrong, then explain why the following executes.
on test()
log class of test as text
end test
property y : test
set x to test
log class of x as text
log class of y as text
x()
y()
This is not an answer to the original question. This is in response to foo’s comment made on December 1. It is an example of how to create two instances of the same script boy which share a common record. Also, having learned from foo's comment, I used a record to share properties with all the script instances. I don’t know if this is the best way to do it, but at least there are no globals.
script mom
property hair : "blond"
property shared : {address:"12 walnut st", phone:"555-1234"}
end script
script boy
property parent : mom
end script
script girl
property parent : mom
end script
on clone from old given shared:sharedSwitch as boolean : false
if sharedSwitch then
set shared to shared of old
set shared of old to missing value
end if
copy old to new
if sharedSwitch then
set shared of new to shared
set shared of old to shared
end if
return new
end clone
property myboy : clone from boy with shared
on run
log "mom hair is" & tab & tab & hair of mom
log "boy hair is " & tab & tab & hair of boy
log "girl hair is " & tab & tab & hair of girl
log "myboy hair is " & tab & hair of myboy
set hair of boy to "redhead"
log "**Set boy hair to redhead**"
log "mom hair is" & tab & tab & hair of mom
log "boy hair is " & tab & tab & hair of boy
log "girl hair is " & tab & tab & hair of girl
log "myboy hair is " & tab & hair of myboy
set hair of myboy to "flattop"
log "**Set myboy hair to flattop**"
log "mom hair is" & tab & tab & hair of mom
log "boy hair is " & tab & tab & hair of boy
log "girl hair is " & tab & tab & hair of girl
log "myboy hair is " & tab & hair of myboy
log
log "mom phone is" & tab & phone of shared of mom
log "boy phone is" & tab & phone of shared of boy
log "girl phone is" & tab & phone of shared of girl
log "myboy phone is" & tab & phone of shared of myboy
set phone of shared of myboy to "555-9999"
log "**Set myboy phone to 555-9999**"
log "mom phone is" & tab & phone of shared of mom
log "boy phone is" & tab & phone of shared of boy
log "girl phone is" & tab & phone of shared of girl
log "myboy phone is" & tab & phone of shared of myboy
end run