DekGenius.com
[ Team LiB ] Previous Section Next Section

7.5 Script Properties

A script property (often just called a property) is a script-level global variable with initialization. A script property must be declared, and an initial value must be supplied as part of the declaration. The syntax is:

property propertyName : initialValue

For example:

property x : 5

The abbreviation for property is prop.

A property declaration can appear only at top level or at the top level of a script object. For example:

property x : 5
script myScript
        property y : 10
        -- other stuff
end script
-- other stuff

A property is a variable, so its value can be set and fetched in the normal way. For example:

property x : 10
display dialog x -- 10
set x to 5
display dialog x -- 5

7.5.1 Scoping of Properties

A property is a kind of global variable, and a property declaration has the same downward effect as a global declaration:

property x : 10
script myScript
        display dialog x
end script
on myHandler(  )
        display dialog x
end myHandler
run myScript -- 10
myHandler(  ) -- 10

Both myScript and myHandler can see the property x, because the property declaration works like a global declaration with respect to its downward effects.

The big difference between a global variable and a script property is in the upward effect of their declaration. A property's scope is confined to the script object where it is declared. The property is automatically visible downwards, as if the property declaration had been a global declaration; but it is not automatically visible anywhere else. Different script objects may declare a property by the same name, and these properties will be separate variables.

For example:

property x : 5
script scriptOne
        property x : 10
        script scriptTwo
                property x : 20
                display dialog x
        end script
        display dialog x
        run scriptTwo
end script
script scriptThree
        property x : 30
        display dialog x
end script
script scriptFour
        display dialog x
end script
display dialog x -- 5
run scriptOne -- 10, 20
run scriptThree -- 30
run scriptFour -- 5

Every property x in that code is a separate variable. Observe that this separateness would be impossible using global declarations, because each global x declaration at any level would refer to the very same top-level global variable. Of course, locals provide a similar separateness, but with locals you wouldn't get the downward effect of a property declaration (used by scriptFour to see the top-level x). Thus we see that the scoping effect of a property declaration is different from either a global declaration or a local declaration.

Furthermore a property, unlike a local, even in scopes where it isn't visible automatically, is visible on demand wherever its script object is visible. To speak of a property from outside the scope where it is visible automatically, you must employ a special syntax: either you use the of operator (or the apostrophe-ess operator) and the name of the script object, or you use the keyword its within a tell block addressed to the script object. You are then free both to fetch and to change the value of the property.

For example:

script myScript
        property x : 10
end script
on myHandler(  )
        set myScript's x to 20
end myHandler
display dialog x of myScript -- 10
myHandler(  )
display dialog myScript's x -- 20
tell myScript
        display dialog its x -- 20
end tell

A difficulty arises, though, when a script object has a property but wishes to speak of a top-level property of the same name:

property x : 5
script myScript
        property x : 10
        display dialog x -- but I want to speak of the top-level x
end script
run myScript -- 10, alas

The difficulty is that the top-level script is anonymous. Under normal circumstances, it may be referred to at any level as parent. For example:

property x : 5
script outerScript
        property x : 10
        script innerScript
                property x : 20
                display dialog parent's x
        end script
end script
run outerScript's innerScript -- 5 (not 10 or 20)

However, it is possible to subvert this by redefining a script object's parent. (This will be explained in Section 9.7.) For example:

property x : 5
script scriptOne
        property x : 10
end script
script scriptTwo
        property x : 20
        property parent : scriptOne
        display dialog parent's x
end script
run scriptTwo -- 10 (not 5)

To get around this, the surest method, and therefore the surest method for accessing a top-level property in general, is to give the top level a name. This is done by assigning the value me to a global variable or property at top level. (For the formal explanation of me, see Section 10.5.) So, for example:

property topLevel : me
property x : 5
script scriptOne
        property x : 10
end script
script scriptTwo
        property x : 20
        property parent : scriptOne
        display dialog topLevel's x
end script
run scriptTwo -- 5

7.5.2 Top-Level Properties Are Globals

There is no difference between a top-level global variable and a top-level property (except that the property is initialized). I will pause a moment to let this sink in.

One consequence of this is that in all the examples in the previous section where I declared a top-level property, I could have used a top-level global instead. This top-level global can be explicit (if I want the downward effects of the declaration) or implicit. For example, I'll just repeat the last example in a different guise:

global topLevel
script scriptOne
        property x : 10
end script
script scriptTwo
        property x : 20
        property parent : scriptOne
        display dialog topLevel's x
end script
set topLevel to me
set x to 5
run scriptTwo -- 5

In that version of the code, topLevel and x (at top level) are global variables, not properties. This changes essentially nothing. scriptTwo still speaks of toplevel's x, regardless. There is a declaration of topLevel as global, so that scriptTwo will be able to see it (the downward effect of the declaration), and it is assigned the value me so that scriptTwo can refer to the top level by name. x is an implicit global that comes into existence when it is set in the next-to-last line. The really interesting part of the example is this line:

        display dialog topLevel's x

Here, scriptTwo can access the global variable x by referring to it in terms of the top level's name, just as if x were a property. And it can do this even though there has never been, and never will be, an explicit global declaration for x. This is because the compiler is satisfied by the specification topLevel's x; it knows just where to look for this x, and that's all the compiler wants to know. At runtime, by the time scriptTwo runs, the x in question has a value, and all is well.

The upward effect of a global declaration identifies the declared variable with a top-level property, just as it would with a top-level global variable. For example:

property x : 5
script outerScript
        property x : 10
        script innerScript
                global x
                display dialog x
        end script
end script
run outerScript's innerScript -- 5

The global declaration of x in innerScript identifies x in this scope with the top-level property of the same name. We thus have another way of jumping past the scope where x is 10 to see the x at top level.

7.5.3 Delayed Declaration of Properties

Because of the nature of AppleScript's one-pass compiler, a property declaration may appear anywhere in its scope, not just at the start. It still provides the initial value for the variable at the start of its scope, not merely from the point where the declaration appears.

So, for example, this script runs, and displays 10:

display dialog x
property x : 10

The property declaration is dealt with by the compiler, so before the script starts running x already exists and has the value 10. Thus the first line of the script works even though no definition of x precedes it. Even though it works, this is poor style and is to be discouraged.

7.5.4 Redeclaration of Properties

It is not a compile-time error to redeclare a property as a local or a local as a property; but access to the property is lost within that scope. For example:

script myScript
        property x : 4
        display dialog x
        local x
        display dialog x
end script
run myScript -- 4, then error

The second attempt to display x fails because by that point x has been redeclared as local, and this local has no value. But the downward effect of the property declaration remains, so the property remains accessible at a deeper scope. Thus:

script myScript
        property x : 10
        local x
        set x to 20
        on myHandler(  )
                display dialog x
        end myHandler
        myHandler(  )
        display dialog x
end script
run myScript -- 10, then 20

It is a compile-time error to redeclare as global a variable declared as a property in the same scope:

property x: 10
global x -- compile-time error

It is not a compile-time error to do it the other way round, redeclaring a global as a property. This is merely taken as a delayed declaration of the property, and the global declaration has no effect. So:

global x
set x to 10
script myScript
        global x
        set x to 5
        property x : 20
        display dialog x
end script
run myScript -- 5
display dialog x -- 10

Within myScript, x is a property throughout; the global declaration inside myScript has no effect. The property x starts out with the value 20 before myScript runs, but myScript then sets it to 5, and this is the value that is displayed in the first dialog. The second dialog shows that the global x is unaffected. This code was written and executed on a closed course by a trained driver; please, do not attempt.

    [ Team LiB ] Previous Section Next Section