Please Pass the Handler
Please Pass the Handler
- Subject: Please Pass the Handler
- From: Arthur J Knapp <email@hidden>
- Date: Fri, 11 Jan 2002 16:40:57 -0500
In some programming languages, you can pass a handler, (function or
subroutine), to another handler, so that the passed handler can
provide custom functionality. A typical example would be JavaScript's
sort() method of arrays, where you pass a comparison function that
tells sort() how to compare any two items in the array.
In AppleScript, it has been shown that a handler can be passed
around as a parameter, but that the act of actually calling the
handler is complicated by AS's bizarre variable-scope rules.
The following are techniques that allow handlers-as-parameters,
ending with a new realization that I had today:
This is how NOT to pass a handler as a parameter:
on PassThisHandler()
return "Successful !!!"
end PassThisHandler
on CallTheHandler( handlerParameter )
return handlerParameter()
end CallTheHandler
CallTheHandler( PassThisHandler )
--
--> error "<<script>> doesn't understand the handlerParameter message."
As you can see, the calling handler can't treat one of it's paramters
as a handler.
One way to deal with the scope problem is to have the calling handler
set it's parameter to a top-level property:
on PassThisHandler()
return "Successful !!!"
end PassThisHandler
property gHoldTheHandler : missing value
on CallTheHandler( handlerParameter )
set gHoldTheHandler to handlerParameter -- Set
set returnValue to gHoldTheHandler()
set gHoldTheHandler to missing value -- Restore
return returnValue
end CallTheHandler
CallTheHandler( PassThisHandler ) --> "Successful !!!"
This seems to work because, (I guess), properties and handlers share
the same scoping rules in AppleScript. The major problem with the
above technique is the set/restore procedure. I suppose you don't
*have* to clear the passed-handler from the property, but it seems
like good coding practice to do so.
A different way to go about this is to give up passing handlers
around, and to simply pass script objects around, containing the
handler you want to use:
script HoldTheHandler
on PassThisHandler()
return "Successful !!!"
end PassThisHandler
end script
on CallTheHandler( scriptParameter )
return PassThisHandler() of scriptParameter
end CallTheHandler
CallTheHandler( HoldTheHandler ) --> "Successful !!!"
Right away, you'll notice the problem that this technique
requires the calling handler to know the name of the handler
in the script object, which makes this system less flexable.
One way to avoid using a top-level script object, and to get
away from the calling handler having to know the name of the
passed-handler, is to simply have the calling handler create
it's own script object:
on PassThisHandler()
return "Successful !!!"
end PassThisHandler
on CallTheHandler( handlerParameter )
script HoldAHandler
property theHandler : handlerParameter
end script
return theHandler() of HoldAHandler
end CallTheHandler
CallTheHandler( PassThisHandler ) --> "Successful !!!"
I think I like this method the best, as it allows the calling
handler to define it's own names for things, ie: it doesn't
have to know that the handler's defined-name is PassThisHandler.
In any case, I just realized today that there is yet one more
trick that can be used:
on PassThisHandler()
return "Successful !!!"
end PassThisHandler
on CallTheHandler( scriptParameter )
return PassThisHandler() of scriptParameter
end CallTheHandler
CallTheHandler( me ) --> "Successful !!!"
Notice, we've gone back to passing a script object, but we
don't have to create a script object, because *me* is a
script object, refering to your entire script!!!
Now, on the face of it, this might seem silly. If the calling
handler knows the name of the passed-handler, why doesn't it
just call it directly:
on PassThisHandler()
return "Successful !!!"
end PassThisHandler
on CallTheHandler()
return PassThisHandler()
At least one good reason would be when working with script
libraries, ie: you've loaded a compiled script via the
"load script" command. These loaded scripts, unfortunately,
do not have access to your script's top-level namespace. By
passing "me" as a parameter, you've given the loaded script
complete access:
-- compiled script file "ScriptLib"
--
on DoSomthing( scriptParameter )
-- stuff
GetValue() of scriptParameter
-- more stuff
end DoSomthing
-- your script
--
on GetValue()
return -- something
end GetValue
set ScriptLib to load script "MacHD:ScriptLib"
DoSomthing( me ) of ScriptLib
Of course, we've gone back to having to know the actual
defined-name of the handler, but it's another tool for
our scripting tool belt. :)
P.S. If I've confused everybody, I'm sorry. Scott Norton will
no doubt set things straight once he reads this. :)
{ Arthur J. Knapp, of <
http://www.STELLARViSIONs.com>
<
mailto:email@hidden>
(*) Happy
( ) Sad
( ) Ambivalent
( ) Ubiquitous
}