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.

See the video below, which discusses how to use handlers to modularize and parameterize scripts for efficiency:

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.

Note: 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

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.

The example below adds an addToTotal command message. If a parameter is passed with the message, its value is available in the newAmount variable, otherwise that variable is empty.

on handlerName {{with | of| given} {a | an | the} paramName1 {, paramName2...} }

statements

end handlerName

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 functionName

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.

Note: If the 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.

Note: 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 names 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). For example, here is a function that will calculate the quotient of two numbers, after first checking for a zero divisor:

function quotient of dividend, divisor

if divisor is zero then return zero

else return dividend/ divisor

end quotient

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 parameters passed by the calling function. In SenseTalk, commands and functions can be called with any number of parameters, regardless of what a handler may be expecting. If fewer values are passed in by the calling script than the number of named parameters in a handler, the named parameters for which there are no initial values will be set to empty.

If more values are passed to a handler than the number of named parameters that it declares, the additional values can be accessed from within the handler by using the param or parameterList functions. The number of parameters that were passed in can be obtained by the paramCount function. Here is an example that uses these functions to find the median (middle) value from among all of the parameter values that are passed to it, ignoring any values that are not numbers:

to handle medianNumber

set numList to be an empty list

repeat with n=1 to the paramCount-- Step through all parameters

if param(n) is a number then insert param(n) into numList

end repeat

 

sort the items of numList in numeric order

return the middle item of numList

end mediaNumber

Another way to handle a variable number of parameters passed to a handler is to list one or more variable names after the handler name (or in a params declaration), and follow the last variable name with three dots (...). By doing this, that variable will be set to a list containing all of the additional parameters:

to quoteAndJoin given joiner, stuffToJoin...

get stuffToJoin joined by (quote & joiner & quote)

return quote & it & quote

end quoteAndJoin

Advanced Message Handling

Handling Any (<any>) Messages

Each handler will handle messages with only one name. So, a to drive handler will only be called when a drive message is sent. On rare occasions, it may be helpful to create a handler that can receive messages with any name. This can be done by specifying <any> instead of a message name. This capability may be particularly useful in a getProp handler or in a script in the frontScripts.

There are a few special rules associated with these <any> handlers. If a script has a handler for a specific message, that handler will be called rather than the <any> handler — the <any> handler will only be called for messages that would otherwise not be handled by that script. Due to the unique ability of an <any> handler to handle any message that comes along, it is specially blocked by SenseTalk from calling itself. Otherwise it would quickly become a recursive nightmare as each command in an on <any> handler would cause it to call itself.

The use of <any> handlers should be approached with caution in order to avoid blocking messages unintentionally. The param(0) function can be used to obtain the name of the actual message sent, in order to select the appropriate action or to pass messages that the handler is not intended to deal with:

on <any>

if param(0) does not begin with "x_" then pass message

-- Put code here to handle commands beginning with x_

end on <any>

Handling Undelivered Messages

When a message is sent for which no handler is found, rather than immediately raising an error, SenseTalk sends an undeliveredMessage message to the target of the original un-handled message. An object can implement an undeliveredMessage handler to try passing the original message to some other object which may be able to handle it (see the pass original message to ... command), or dealing with the problem in some other way. If the undeliveredMessage handler executes a pass undeliveredMessage command, the usual error will be raised.

A pass original message to object command may be used to try passing an undelivered message to some other object. If that object handles the message, that will be the end of it, and execution of the current handler will end. If the object does not handle the original message, execution will continue. In this way, an undeliveredMessage handler can attempt to deliver the original message to one or more other objects which may be able to handle it.

to handle undeliveredMessage

repeat with friend = each item in my friends

pass original message to friend

end repeat

pass undeliveredMessage -- Give up and let it fail

end undeliveredMessage

GetProp, SetProp Handlers

In addition to the standard command and function handlers, an object’s script may include two special types of handlers for working with the object’s properties: getProp handlers for providing the value of a property, and setProp handlers for receiving a new value for a property.

Whenever a property of an object is being read, a getProp message for that property is sent to the object. If it handles the message, the value it returns is used as the value of that property. When the value of a property is changed, a setProp message is sent to the object, with the new value as a parameter. If the object has a setProp handler for that message, it is called, otherwise the property is set directly.

For example, here is a handler that will supply the area property of an object, based on its length and width:

getProp area

return my length * my width

end area

An object may also want to control setting a property. Here, setting the area of an object will actually change its length:

setProp area newArea

set the length of me to newArea

my width

end area

If an object accesses one of its own properties from within a getProp or setProp handler for that property SenseTalk will access the property directly rather than calling the getProp/setProp handler recursively.

My Direct Property

Behavior: Enables an object to access its own properties without sending any function or getProp/setProp messages. This can be done using the special syntax my direct propName (or my direct property propName).

Syntax:

my direct propName

my direct property propName

Example:

getProp age -- My age in years

return (the date - my direct birthDate) div 365.25 days

end age

Note: The direct keyword can only be used with my, and is, therefore, limited to an object accessing its own properties. Access to another object’s properties will always involve calling getProp or setProp.

HandlerNames Function

Behavior: Returns a list of the names of each of the handlers in an object's script. The order in which the handlers are listed is undefined.

Syntax:

the handlerNames of anObject

handlerNames(anObject)

Example:

put handlerNames of Account

 

This topic was last updated on July 09, 2020, at 01:18:47 PM.

Eggplant icon Eggplantsoftware.com | Documentation Home | User Forums | Support | Copyright © 2020 Eggplant