Handlers
Handlers are message listeners within a script. An object has a script, which has handlers. The object must have access to a handler for a particular message in order to receive that message and act on it. For more on messages, see Messages.
An object’s behaviors are defined by the way it handles different messages that may be sent to it. When an object receives a message, it will respond and perform a scripted action, but only if it has a script with a handler for that particular message. All scripts consist of one or more handlers for the various messages that the object is interested in handling (including the initial handler of a script, which handles a message by the same name as the script). If an object receives a message for which it doesn’t have a matching handler, it ignores that message.
A SenseTalk script is made up of handlers. A handler is a part of a script that defines what the script will do when a particular message is sent to it. There are three primary types of handlers: command handlers (sometimes called on handlers), function handlers, and generic handlers (also known as to handlers). There are also two special types of handlers, getProp and setProp handlers, discussed in Properties.
Types of Handlers
Command, Function, and Generic Handlers
There are three primary types of message handlers: generic, command, and function handlers. Generic handlers begin with to handle
(or simply to
) and can handle both command and function messages. For simplicity, always use generic handlers unless there is a special need to handle command and function messages differently. Command handlers begin with the word on
and handle messages sent by commands. A command handler typically performs a series of actions. Function handlers, which begin with the word function
, handle function call messages, and return a value.
It should be noted that a command handler may also return a value, and a function handler may perform actions in addition to returning a value. The only real difference between the handler types is the kind of messages they will handle: a command handler will never be run as a result of a function message, and a function handler will never be called by a command message.
If a script contains both a generic handler (to
) and a specific handler (on
or function
) for the same message name, the specific handler always receives priority and receives the message. The to
handler still receives messages of the other type. If a script contains all three types of handlers for a particular message, the on
handler receives command messages by that name, the function
handler receives function messages, and the to
handler is never called.
The following is a very simple handler for a greetTheUser
message:
to greetTheUser
put "Welcome to SenseTalk. Happy scripting!"
end greetTheUser
To
, To Handle
Keyword
Behavior: The to
or to handle
keyword declares a generic handler that can receive both command and function messages. If the handler needs to take different actions depending on how it was called, the messageType
function can be used to find out whether the handler was called as a command or as a function.
When the script receives either a command message or a function message matching messageName, the statements of this handler are executed. The incoming parameter values passed to the handler is assigned to the corresponding parameter names (paramName1 , paramName2, paramNameN) declared following the messageName.
Syntax:
to {handle} messageName {{with | of | given} {a | an | the} paramName1 {, paramName2 ...} }
statements
end [messageName | handler | to {handle}]
Example:
to handle increaseSize given amount
if amount is empty then add 1 to my size else add amount to my size
end increaseSize
On
Keyword
Behavior: The on
keyword is used to declare a command handler, and an end
keyword ends it.
When an object receives a command message matching handlerName, the statements of that handler are executed. The incoming parameter values passed to the handler are assigned to the corresponding parameter names (paramName1 , paramName2, paramNameN) declared following the handlerName.
Syntax:
on handlerName {{with | of | given} {a | an | the} paramName1 {, paramName2 ...} }
statements
end [handlerName | handler | on]
The example below defines an addToTotal
command handler. If a parameter is passed with the message, its value is available in the newAmount
variable, otherwise that variable is empty.
Example:
on addToTotal newAmount
add newAmount to global total -- Store total in a global variable
end addToTotal
Function
Keyword
Behavior: The function
keyword declares a function handler. When the script receives a function message matching functionName, the statements of this handler will be executed. The incoming parameter values passed to the handler will be assigned to the corresponding parameter names (paramName1 , paramName2, paramNameN) declared following the functionName. The returnValue will be passed back to the calling script as the value of the function call.
Syntax:
function handlerName {{with | of | given} {a | an | the} paramName1 {, paramName2 ...} }
statements
return returnValue
end [handlerName | handler | function]
Example:
function getTotal
return global total
end getTotal
Initial Handlers
In addition to explicitly-declared handlers beginning with the to
, on
, and function
keywords, a script has an initial handler, consisting of all of the statements from the beginning of the script (after skipping any properties declarations at the very beginning of the script) to the first explicit handler or properties declaration. The initial handler type is actually the most common; any script that has no explicit handlers is just an initial handler. What we describe as a "script" is actually an initial handler.
The initial handler is treated as a generic to handle
type of handler, which will handle any messages with the same name as the script (less any extension and illegal characters), and can respond to both command and function messages. In the case of an unnamed object (one that is created as a property list in a script, rather than loaded from a script file), the initial handler can be called using the run
command or function. For objects other than script files, the initial handler is assigned the name <initialHandler>
.
The only way to declare parameters in an initial handler is to use a params declaration.
If a script actually contains a named handler by the same name as the script (such as “to handle scriptFileName
”), that handler takes precedence, and the initial lines of the script prior to the first named handler are ignored.
When a message is sent to a script object that resides on disk, SenseTalk reads that script file and caches the script in memory. If the object then receives another message, SenseTalk can check very quickly whether it has a handler for that message. In some (fairly rare) situations it may be desirable to have SenseTalk check for updates to the script during a run. In these situations, you can set the watchForScriptChanges
global property to true (the default setting is false). This will cause SenseTalk to check the file for updates each time the object receives a message. If the file has been updated, it will be read again, and its new handlers will be used. The executing version of a handler is not changed while it runs.
Receiving Passed Parameters
When a handler expects to receive parameters passed to it by the calling script, it can list variables for those parameters following the message name (or in a params
declaration on the first line within the handler—particularly useful in an initial handler).
Parameters can be passed either sequentially, or using key:value pairs that can be received as named parameters. Sequential parameters act like you might expect - they pass parameters in order, and the called handler must be set up to receive these values in that order. Named parameters use key:value pairs that allow you to refer to the property value by its name within the handler, and so access the information that way. For more information on how different parameters can be passed, see Parameters and Results.
Example:
Here is an example of a basic function handler that will calculate the quotient of two numbers, after first checking for a zero divisor. The words dividend
and divisor
in this example are treated like local variables within the quotient handler, with initial values already assigned to them from the first two sequential parameters passed by the calling function.
function quotient of dividend, divisor
if divisor is zero then return zero
else return dividend/ divisor
end quotient