Online Book Reader

Home Category

AppleScript_ The Definitive Guide - Matt Neuburg [98]

By Root 1461 0
that the mere act of assigning a script object variable to another variable—it can equally be a copy as a set—causes the script object to become a closure . A closure is a scope block plus the values of its free variables at that moment.

The example is structured in three parts so as to demonstrate the phenomenon fully. First, a property declaration precedes the script definition; this is how x inside the script definition becomes a free variable at compile time. Then, the script object is assigned to another variable; at that moment the closure is formed. The free variable has a different value by this time, so this is the value that gets frozen into the closure. Finally, the free variable's value is changed again and the script object is executed; but the script object was already turned into a closure, so the change in the value of top-level x has no effect on it.

If, at the start of that example, we substitute a global declaration for the property declaration, the example doesn't work: we don't get a closure. Rather, the dialog displays 10, the value of x at the moment the handler is executed—the normal, nonclosure behavior. So only free variables whose value is supplied by a top-level entity can form a closure.

Closures and Handlers


So far, we've generated a closure in accidental circumstances. In fact, this feels like a bug; the mere act of assigning a script object to a variable hardly seems to warrant freezing that same script object into a closure, and seems to be more a trap we might fall into, causing our script to misbehave mysteriously, than a feature we would use deliberately. Now, however, let's turn our attention to a situation where we might actually like to generate a closure: when returning a script object from a handler.

Sure enough, it works. A closure is generated at the time we run the handler and generate the script object. Whatever the value of the script object's free variables are at that moment, if that value comes from a top-level entity, that's the value they retain:

property x : 5

on h( )

script myScript

display dialog x

end script

return myScript

end h

set x to 10

set s to h( )

run s -- 10

set x to 20

run s -- 10

set x to 30

run s --10

As before, if we replace the property declaration in the first line with a global declaration, there's no closure, and the dialogs say 10, then 20, then 30. Similarly, if we put a global x declaration at the start of h, there's no closure. To get a closure, we need a top-level entity to come shining down from above into our script object's scope.

Because we're inside a handler, there's one more type of variable we need to consider. Remember, a script object inside a handler can see the handler's locals. So a handler's locals can be free variables in the script object. Can they generate a closure? Yes, they can:

on h( )

local x

set x to "howdy"

script myScript

display dialog x

end script

return myScript

end h

set s to h( )

run s -- howdy

A handler's parameter variables are locals. This means we can feed a parameter into a handler and capture it in a closure produced by the handler:

on scriptMaker(what)

script myScript

display dialog what

end script

return myScript

end scriptMaker

set s to scriptMaker("Hello")

run s -- Hello

Wait—do you recognize that example? It comes from "Handler and Script Object as Result" in Chapter 9, except that there's a line missing. Previously, we captured the handler's parameter in the script object by initializing a property to it:

property x : what

Now it turns out that, thanks to closures, there was no need for that line. Similarly, we could rewrite the makeFilterer example (from the same section) to use a closure, changing the name criterion to crit everywhere and eliminating this line:

property criterion : crit

I hope I'm communicating a sense of how marvelous closures are. A script like this shouldn't even be possible. The parameter what is local to the handler scriptMaker, and goes out of scope—ceases to exist—when scriptMaker finishes executing. Nothing in myScript

Return Main Page Previous Page Next Page

®Online Book Reader