Parameters and Results
Messages are identified by a single word — the message name — but they can also include additional information in the form of parameters. Parameters are values that are passed to commands or functions. These commands or functions may be custom handlers, which can either be located within the calling script, or in another script or helper suite. For more information on declaring handlers and receiving parameters, see Handlers
Two Ways to Pass Parameters: Sequential and Named
There are two ways to pass parameters when calling a command or function: sequentially, or by name. Sequential parameters are passed in sequence, as you might expect. Named parameters are passed as a property list of key:value pairs, with each key being used to match the name of a parameter on the receiving end. The two methods of passing parameters can also be combined.
The calling command or function can be in the same or a different script from the handler being called. The call is often in a separate script, which is helpful for the modularization of tests. A test structure might include a primary script with a number of different calls in it out to other scripts containing a wide variety of handlers that execute different tasks.
If you are interested in pre-defining a default value for any parameter the receiving handler might expect, see Default Parameter Values. For information on writing handlers to receive parameters, see Handlers.
Sequential Parameters
Passing Sequential Parameters
To pass parameters sequentially, simply list the parameter values after the command name separated by commas, or enclosed in parentheses after the function name when calling a function (there are some other variations for functions when only a single parameter value is being passed — see Calling Functions).
The command put "Hello, World!" sends the string “Hello, World!” as a single parameter along with the put
message. To send more than one parameter, just list them with commas in between.
Example: Passing Sequential Parameters with a Command
This example passes three parameters to the doSomethingImportant
command as sequential parameters: the number 31
, the text green
, and the variable style
:
doSomethingImportant 31, "green", style
Command parameters should not be enclosed in parentheses (unless the intent is to pass a list as a single parameter).
Example: Passing Sequential Parameters with a Function
To include parameters with a function call message, list them inside the parentheses after the function name:
put roundToNearest(salary/12, 0.01) into monthlyPayTothePenny
Example: Supplying an Empty Parameter
Two commas in a row imply an empty parameter, and a final comma at the end of a list is ignored, so the following passes three parameters ("silverBar"
, ""
, and 16
):
get verifyQuantity("silverBar",,16,)
Sequential Parameter Assignment
When parameters are passed sequentially, their values are assigned (in the same order) to any parameter variables that are part of the handler declaration. If the caller passes fewer values than the number of parameter variables, those that aren’t assigned will receive their default values (or empty). If the caller passes more values, the handler can access them using the parameterList
function, the paramCount
function and the param
function.
Examples:
For example, consider a castSpell
handler declared like this:
to castSpell spellName, duration, potency -- the castSpell handler declares three parameter variables
//Do things to cast the spell:
Put duration and potency into Cauldron
Stir Cauldron -- A custom call that executes the spell
Log "Alakazam!: " & spellName -- A message confirming that the spell has been cast
end castSpell
Here, spellName
, duration
, and potency
are the parameter variables that will receive the values of parameters that are passed when the handler is called.
If the above handler is called using the command castSpell "sleep", 12 hours, "deep"
, then the whole script might look like this:
castSpell "sleep", 12 hours, "deep" --This is the calling command, passing three parameters sequentially
to castSpell spellName, duration, potency --The sequentially passed parameters are received in order and inserted into their corresponding parameter variables
//Do things to cast the spell:
Put duration and potency into Cauldron
Stir Cauldron -- A custom call that executes the spell
Log "Alakazam!: " & spellName -- A message confirming that the spell has been cast
end castSpell
In this case, the value “sleep” will be assigned to the parameter variable spellName
, the value 12 hours will be assigned to duration
and “deep” will be assigned to the potency
variable.
Suppose the same handler is called using the command castSpell "sleep"
:
castSpell "sleep"
to castSpell spellName, duration, potency
//Do things to cast a spell!
TypeText "Alakazam!"
end castSpell
In this case only a single parameter value is supplied. The value “sleep” is assigned to the parameter variable castSpell
as before, but because there are no values given for the duration
and potency
variables they are initialized to their default values or (as in this case, since the handler doesn’t define any default values) to empty
.
The handler could also be called with more parameter values than there are parameter variables:
castSpell "sleep", 12 hours, "deep", stardust
to castSpell spellName, duration, potency
//Do things to cast a spell!
TypeText "Alakazam!"
end castSpell
In this case the first three values are assigned to the three parameter variables as usual. The additional value, stardust, is not assigned to any variable, but is available within the handler using the param
function, as param(4)
. The number of sequential parameter values that were passed by the caller is available using the paramCount
function, which in this case would return a value of 4
. And the full list of sequential parameters that were passed is available as the parameterList
.
The called handler can also use an ellipsis or three periods (…
) to explicitly accept any number of parameters. For more information on how this is received by the handler, see Accepting a Variable Number of Parameters.
Named Parameters
Passing Named Parameters
The second method of passing parameters is by name. To pass parameters by name, use a property list (or a sequence of key:value pairs) followed by the words by name
. The handler should be set up with property variables to receive the appropriate values.
Using by name
has no effect if the final parameter given is not a property list or a sequence of key:value pairs.
Examples:
All of these examples show various ways of passing the same parameters as a property list, with both commands and functions.
Different ways of passing a property list by name to a command:
orderItem aPropertyList by name
orderItem {id:a, size:b, color:c} by name
orderItem id:a, size:b, color:c by name
Different ways of passing a property list by name to a function:
put itemInformation({id:a, size:b, color:c} by name)
put itemInformation(id:a, size:b, color:c by name)
Named Parameter Assignment
Any values that are passed by name are assigned to parameter variables with the same name. In order to pass named parameters, pass a property list as the only parameter, followed by the words by name
. When a property list parameter (or sequence of key:value pairs) is passed by name
, each parameter variable in the called handler is assigned the value of the property in the property list with the same name as the variable.
The full set of values that were passed by name is available from within the called handler using the parametersByName
function.
Example: Passing a property list by name
In this example, the spellName
variable is assigned the value of the spellName
property from the property list, the value of the duration
property is assigned to the duration
parameter variable, and so forth. If the property list doesn’t have a matching property name for one of the parameter variables, that variable begins with its assigned default value (or empty if there is no default value).
set deepSleep to {spellName:"sleep", potency:"deep"} -- This stores the property list in a variable before it is passed
castSpell deepSleep by name -- Calls the castSpell handler, passing a single property list. The 'by name' keywords cause the property list values to be assigned to parameter variables whose names match the property keys
to castSpell spellName, duration, potency --The parameters passed by name are received and their values inserted into the corresponding parameter variables
//Do things to cast the spell:
Put duration and potency into Cauldron
Stir Cauldron
Log "Alakazam!: " & spellName
end castSpell
The property list being passed by name could also be the result of an expression. For example, this command adds a duration
property to those in the deepSleep
property list and passes the resulting properties by name:
castSpell deepSleep adding {duration: 1 hr} by name
Of course, the property list could also be given directly on the calling line:
castSpell {spellName:"sleep", potency:"deep", duration:15 minutes} by name
Or like this, leaving off the braces:
castSpell duration:15 minutes, spellName:"sleep", potency:"deep" by name
Both Sequential and Named Parameters
It is also possible to pass parameters to a handler using a combination of sequential and named parameters. To do this, simply give the sequential parameters first, followed by the named parameters and the words by name
:
castSpell "sleep", potency:"deep" by name
In this case, the first parameter value, “sleep”, is not named so it is passed sequentially and therefore assigned to the first parameter variable, spellName
. Following this is a property list passed by name
, so the property name potency
is matched to the potency
parameter variable, which is assigned the value “deep”.
Number of Parameters
In SenseTalk, when a command or function is called, it will invoke a custom handler or built-in command or function with that name, regardless of the number of parameters that were passed or expected. If the number of parameters that are passed don't match what is expected by the called handler, it may deal with the difference in various ways: an exception may be thrown; excess values may be ignored; or default values may be assumed for parameters that were not supplied. It is up to the called handler to take what it receives and respond appropriately at runtime. For more information, see Receiving Passed Parameters.
Passing a List as Parameters
Instead of passing individual parameters, you can pass all of the values contained in a list by specifying as parameters
. This will pass the values in the list individually, rather than passing the list as a single entity:
put [candles, 6, blue] into thingsToBeUpdated
updateAllItems thingsToBeUpdated as parameters -- This passes three parameters: the variable candles, the number 6, and the variable blue.
If you do this without "as parameters", the entire list will be passed as one parameter.
This can be especially useful for passing along the list of parameters received by the current handler:
return otherFunction(parameterList() as parameters)
Property Lists as Parameters
As a convenience, when the last or only parameter is a property list, the curly braces can be omitted. When one of these forms is used, all of the individual properties are passed together as a single property list.
Examples:
Both of these examples do the same thing. The only difference is that one leaves off the curly braces for the property list passed as the second parameter.
addAtPosition 23, {item:"paper", quantity:500, color:"White"} -- The first parameter passed is 23, and the second parameter is the property list.
addAtPosition 23, item:"paper", quantity:500, color:"White" -- The first parameter passed is 23, and the second parameter is the property list.
Examples:
addToInventory item:"candles", quantity:6,color:"Blue"-- Passes a property list to the called handler as a single parameter.
set article to fetchClipping(author:"Lewis", title:"Lost")-- Passes a property list to the called function as a single parameter.
Property lists can also be used to pass parameters by name. When parameters are passed by name, they become available within the called handler and can be referred to by their property keys, or "names". For more information on passing parameters by name, see Two Ways to Pass Parameters: Sequential and Named.
Parameters Passed as Containers (by Reference)
Sometimes it is useful for a handler to be able to change one or more of the values in the calling script. In SenseTalk, this can only be done if the calling script allows it, by passing one or more parameters "by reference" or as "containers" (see the description of References to Containers for more details). To illustrate, here is a very simple command handler that swaps two values:
on swapValues a,b
put a into temp
put b into a
put temp into b
end swapValues
If called in the usual way, this command would have no effect in the calling script:
swapValues x,y -- This command leaves x and y unchanged
If the calling script explicitly passes its parameters as containers, though, their values can be changed:
swapValues container x, container y -- This swaps the values in x and y
Syntax:
container aContainer
{a} reference {to} aContainer
refer to aContainer
@ aContainer
Returning Results
A function handler will return a value to the calling script, which is used as the value of the function call expression. If a function handler does not explicitly return a value, its return value will simply be empty. Usually, though, the reason to have a function is to provide a value, so function handlers most often end with a return
statement. A return
statement must include one parameter—the value to be returned (which might be an expression). If needed, multiple values can be returned as a list, as shown here:
return [min(source), max(source), average(source)]
Commands and Functions for Working with Parameters and Results
Params Declaration
Behavior: Declares some named incoming parameters for the initial handler of a script. The params
declaration must be the first statement in the script. It assigns names to the incoming parameters. The parameters can still also be accessed using the param
, paramcount
, and params
functions as described below.
Syntax:
params paramName1 {, paramName2 ...}
Example:
params width,height
Param
Function
Behavior: Returns the value of one of the parameters passed sequentially to the current handler, specified by its ordinal position in the parameter list. A handler can receive any number of incoming sequential parameters, regardless of the number of parameters that it declared. The param
function can be used to retrieve their values from within the handler.
Important: This function only returns the values of sequential parameters. For more information, see Two Ways to Pass: Sequential and Named Parameters.
Syntax:
{the} param of numExpr
param( numExpr )
Examples:
get the param of 1-- gets the first parameter
put param(0)-- shows the handler name
Example:
//Define a list of watering dates
put ["2020-09-06","2020-09-08","2020-09-10","2020-09-11","2020-09-14","2020-09-16"] into WateringDateList
Repeat with each item of WateringDateList
If it = Today
WaterThePlants Today, 2020 -- This second parameter is extraneous and not necessarily expected by the handler being called
end if
End repeat
to WaterThePlants Date -- This line only has one variable declared to catch a passed parameter. Today's date is added to this Date parameter variable.
// Do things to water the plants
--Click "WateringButton"
log "Watering completed on " & Date -- Logs that the watering was completed, as well as the date, which was passed as a parameter
// Check for extra variables, up to 5 places out:
repeat with each [2,3,4,5]
if param(it) does not equal empty then put "Parameter " & it & " is: " ¶m(it) -- If a parameter was passed in any of the positions 2-5, it will print that value to the run window. In this case, it puts "Parameter 2 is: 2020"
end repeat
end WaterThePlants
ParamCount
Function
Behavior: Returns the number of sequential parameters passed to the current handler.
Important: This function only returns the values of sequential parameters. For more information, see Two Ways to Pass: Sequential and Named Parameters.
Syntax:
the paramCount
paramCount()
Example:
repeat with n=1 to the paramCount
put "Parameter " & n & " is " & param(n)
end repeat
Params
Function
Behavior: Returns a text string consisting of the handler name followed by the values of all of the parameters passed to the current handler. Parameter values other than lists and property lists are each enclosed in quotes.
Syntax:
the params
params()
Example:
put the params -- Might show: test "John Doe","27",("JD","Bud")
ParameterList
Function
Behavior: Returns a list containing all of the sequential parameters that were passed to the current handler. Sometimes this might be a more convenient way of working with the parameters that were passed in than using the paramCount
and param
functions. For more information on sequential parameters, see Sequential Parameters.
Syntax:
the parameterList
parameterList()
Example:
repeat with each item of the parameterList
add it to total
end repeat
return func(the parameterList as parameters)
-- pass our params to func
ParametersByName
Function
Behavior: When used from within a called handler, the parametersByName
function returns the full property list passed, including values that may not have been assigned to any parameter variable, either because there was no matching variable name, or because that variable's value was given by a sequential parameter. This function can be helpful in identifying mis-alignments between parameters passed and what is expected on the receiving end.
Syntax:
the parametersByName
parametersByName()
Example:
castSpell {spellName:"sleep", potency:"deep", duration: 12 hours} by name
to castSpell spellName, duration, potency
put the parametersByName -- Accesses the full property list passed to the handler and prints it to the Run window
end castSpell
Example:
//Define a list of watering dates
put ["2020-09-06","2020-09-08","2020-09-10","2020-09-12","2020-09-14","2020-09-16"] into WateringDateList
Repeat with each item of WateringDateList
If it = Today
WaterThePlants {Date: Today, extra: 2020} by name -- This second parameter is extraneous and not necessarily expected by the handler being called
end if
End repeat
to WaterThePlants Today -- this line only has one variable declared to catch a passed parameter
// Do things to water the plants
Click "WateringButton"
// Put all of the received parameters:
put parametersByName() -- Uses the parametersByName function to access the full list of parameters. Puts "{Date:"2020-09-06", extra:2020}"
end WaterThePlants
Return
Command
Behavior: Returns the result of a function when used in a function handler, or sets the result
if used in a message handler.
Syntax:
return {expression}
Example
return pi*diameter
Related:
Result
Function
Behavior: Returns the result (if any) set by the previous command. Most commands which operate on files, for example, will set the result
to empty if they succeed, or to a message indicating what went wrong if they fail.
Syntax:
the result
result()
Example:
if the result is not empty then throw "Error", the result
At the beginning of each statement the result
is set to the result produced by the previous statement. To determine the result of an operation, therefore, you must call this function as part of the very next statement executed.
When a return
statement is executed as part of a handler that was called as a command (rather than as a function), the return value sets the result
in the script which called it.
The following commands will set the result
to something other than empty under some conditions: answer
, ask
, convert
, copy
, create
, delete
, move
, open
, post
, read
, rename
, replace
, seek
, shell
. It can also be set when accessing a file or URL. In testing the result to determine whether the previous command succeeded, it is usually best to check whether the result is empty, rather than looking for specific words in the result, since the exact wording of an error message might change in a future release.
If the throwExceptionResults
global property is set to true, any time a command sets the result
to an exception object (which happens on most error conditions), that exception will be thrown rather than becoming available through this function as described above.
Whenever a non-empty result is set, it is inserted into the resultHistory
global property. This makes it possible for a script to retrieve a result value from an earlier statement. Care must be used, however, to match a result to a particular statement, as empty values are not included. A limited number of results are retained, as specified by the resultHistoryLimit
global property. When this limit is reached, older results are discarded.
If the value returned is an exception object (a property list with an objectType of “exception”) the caller throws the exception if the throwExceptionResults
global property is set to True
.
Related: