AppleScript_ The Definitive Guide - Matt Neuburg [99]
Closures and Stored Script Objects
Closures also come into play when a compiled script file is to be executed with load script or run script (see "Persistence of Top-Level Entities" in Chapter 8). There's more to a compiled script file than meets the eye. The store script command saves a script object into a compiled script file, but it also saves that script object's context , so that if the script object has free variables, it will still work. (You can't see this context unless you use Script Debugger, but it's there.) The load script command loads this context, and the run script command runs within it.
Consider what happens when we create a compiled script file like this:
set f to (path to desktop as string) & "myScript.scpt"
global greeting
set greeting to "Howdy"
property farewell : "Byebye"
script s
display dialog greeting
display dialog farewell
end script
store script s in file f replacing yes
Both greeting and farewell are free variables in the script object s. Only the two display dialog lines are being stored in a compiled script file, but that is not enough information to make sense of these variables. Therefore their context is stored in the file as well.
Tip
Actually, AppleScript makes no attempt to decide at this point what's a free variable and what's not. It just stores the script object's entire context in the file. Thus, in this case, f ends up in the compiled script file as well. This makes no difference to how the stored script object will run, because the script object makes no reference to f. It might make a difference to you if you are strongly security-minded, though, as prying eyes with the proper tools can read the value of f. Also it can make the resulting compiled script file unnecessarily large. A trick to prevent store script from storing unwanted contextual material is to set the script object's parent to AppleScript—but then of course no local context is stored at all (and the rest of the examples in this section will break). Storage of context is an all-or-nothing proposition.
With run script, the situation is simple. No script object is generated. The compiled script file runs within its stored context and that's that:
set f to (path to desktop as string) & "myScript.scpt"
run script alias f -- Howdy, thenByebye
If we use load script to load the compiled script file into a script, things are more complicated. Now we have a script object, and that script object has a context within the current script as well as the context with which it was saved. How will those two contexts interact?
set f to (path to desktop as string) & "myScript.scpt"
set s to load script alias f
global greeting
set greeting to "Bonjour"
property farewell : "Au revoir"
run s -- Bonjour, thenByebye
The first dialog displays the value of greeting from the new, current context. But the second dialog displays the value of farewell from the old, stored context. This result actually makes sense in light of what we already learned about closures. Recall that a free variable whose value is a top-level entity, such as a property, makes a closure; a free variable whose value is a global does not. So the value of farewell, which was stored in the compiled script file as a free variable whose value was a property, is unaffected when the compiled script is loaded into a new context. But in the case of greeting, things are different. This was a global originally, so it does not form a closure. The fact that this is a free variable, however, is remembered; and the variable remains free. When the compiled script file is loaded into our script, it looks to our script to supply a value for this free variable. The supplied value can be a top-level entity (usually a property); it can be a declared global,