DekGenius.com
[ Team LiB ] Previous Section Next Section

11.4 Dereferencing a Reference

Once you have a variable whose value is a reference, AppleScript behaves with confusing inconsistency when you try to use it. In some cases, you can't use the reference without explicitly dereferencing the variable; in other cases, AppleScript dereferences it for you implicitly when you use it. AppleScript can behave both ways with one and the same reference.

When AppleScript performs implicit dereferencing, the reference is completely transparent: it acts precisely as if you were saying the incantation that's frozen inside it. This is exactly the same phenomenon noted in the previous section—you can't learn from a reference that it is a reference, because it acts as if it were the thing referred to.

tell application "Finder"
        set x to folder 1
end tell
name of x -- Mannie
class of x -- folder
set name of x to "Moe"

None of that ought to be possible. A reference's class isn't folder, and a reference doesn't have a name property that you can get and set. In this case, though, it happens that the reference is a reference to a thing whose class is folder and that has a name property. AppleScript dereferences the reference implicitly; it treats the reference as if it were the thing referred to.

But in this example, an attempt to use the same reference transparently runs up against a brick wall:

tell application "Finder"
        set x to a reference to the name of folder 1
end tell
set x to "Moe"

If you were hoping that this would set the name of the Finder's folder 1 to "Moe", you're doomed to disappointment. It didn't: you set the variable x to the string "Moe" (and you lost your reference).

The reason is that the transparency of references can't be permitted to destroy your access to your own variables. Thus, when you perform an assignment, not to a property of a variable that's a reference but to the variable itself, AppleScript stops treating the reference transparently. The assignment is an ordinary assignment to a variable: what's inside the shoebox is thrown away and a new value is put into the shoebox.

Similarly, the boolean equality and inequality operators do not treat references transparently by dereferencing them (Section 15.3). Here's a simple example:

set x to 3
set y to a reference to x
x = y -- false
y = 3 -- false

There's no implicit dereferencing here, and 3 is not the same a reference to x. With other operators, though, AppleScript does dereference, which makes for some paradoxical-looking results:

set x to 3
set y to a reference to x
x = y -- false
x + 0 = y + 0 -- true
x is not less than y and x is not greater than y -- true

In situations where AppleScript doesn't implicitly dereference a reference for you, you can dereference it yourself. The way you do this is with the contents of operator. So, this code renames a folder in the Finder:

tell application "Finder"
        set x to a reference to the name of folder 1
end tell
set contents of x to "Moe"

Here's another example:

set x to 10
set y to a reference to x
set contents of y to 20
x -- 20

Here's the equality example:

set x to 3
set y to a reference to x
x = contents of y -- true

The contents of operator works on any value. If the value isn't a reference, the result of applying the contents of operator is simply the value itself. In this example, the use of the contents of operator (twice) is essentially pointless; AppleScript basically just throws it away, and you end up saying the very same thing you'd say if you simply omitted the words contents of from the code:

set x to contents of "Mannie"
contents of x -- Mannie

You can take advantage of this in dealing with the equality example. Let's say you don't know which of x and y is a reference. That's okay; dereference them both, since it does no harm:

set x to 3
set y to a reference to x
contents of x = contents of y -- true

However, this is not to imply that you can simply use the words contents of capriciously. They do mean something, after all! So, this will cause a runtime error:

set x to "Mannie"
set contents of x to "Moe" -- error

This is like saying set "Mannie" to "Moe", which doesn't work, because "Mannie" is a literal, not the name of a variable.

If a value is a reference to an object belonging to an application, the contents of operator might get you another reference—or it might get you the same reference. So, for example:

tell application "Finder"
        set x to folder 1
end tell
x -- folder "Mannie" of desktop of application "Finder"
set x to contents of x
x -- folder "Mannie" of folder "Desktop" of folder "mattneub" of ¬
        folder "Users" of startup disk of application "Finder"
set x to contents of x
x -- folder "Mannie" of folder "Desktop" of folder "mattneub" of ¬
        folder "Users" of startup disk of application "Finder"

This is entirely up to the target application, and doesn't have any particular significance. In each case you're just telling the application to do a get whose direct object is the very same "phrase" the application handed back to you previously. Whether the application returns the same phrase or a different phrase referring to the same object is entirely its own business.

A problem arises when you're targeting an application whose dictionary defines a contents property for one of its object types. Applications shouldn't do this; it's bad behavior, because they're overlapping with a piece of AppleScript's own built-in vocabulary. In the context of a tell directed at such an application, this raises the question of whether the word contents will be seen as the contents of operator or the application's contents property.

I'm told that the problematic nature of the contents property is actually an AppleScript bug.


An example of such an offender is BBEdit. BBEdit does something I consider very good: when you ask for a text element such as a word, it gives you a reference rather than a string. That's good, because it's then possible to access that element in its context and do things to it. But then BBEdit does something bad: it defines the contents property as your way of obtaining the actual string. (To be quite fair, the fault lies partly with AppleScript itself, which takes the lead by defining a contents property for its selection-object class.)

So, this works to obtain an actual string:

tell application "BBEdit"
        set w to contents of word 4 of window 1
end tell
w -- "test"

But this doesn't:

tell application "BBEdit"
        set w to contents of (get word 4 of window 1)
end tell
w -- characters 11 thru 14 of text window 1 of application "BBEdit"

And therefore neither does this:

tell application "BBEdit"
        set x to word 4 of window 1
        set w to contents of x
end tell
w -- characters 11 thru 14 of text window 1 of application "BBEdit"

The only way to access BBEdit's contents property is within a single expression, as in the first example. You can't apply it to a reference, as in the second two examples, because AppleScript sees that as dereferencing the reference.

The proper behavior would have been for the application to define some other term for obtaining the contents of a thing. Mailsmith, for example, uses a content property of its message class to represent the body of the message. No confusion arises; AppleScript doesn't know that this is the singular of contents. However, Mailsmith then bollixes the user in other ways. The result of asking for the content property is a record where the body text is in an item called contents (see Section 19.3.6). This accounts for the very odd verbiage we were forced to employ in Section 1.3:

set theBody to get contents of content of aMessage

In that line, the contents of operator never appears! First we get the content property of aMessage, which is a record; then we get the contents item of that record. Furthermore, Mailsmith does also let you say contents (instead of content) as the name of this property of the message class. So this code is possible:

tell application "Mailsmith"
        set r to a reference to message 1 of incoming Mail
end tell
get contents of contents of contents of r

In that code, every contents of is necessary in order to arrive at the desired string! The third one dereferences the reference, the second one gets the contents property of the message, and the first one gets the contents item of the resulting record.

    [ Team LiB ] Previous Section Next Section