Variables in SenseTalk
What are Variables?
Variables are named containers. They serve as holders for values, similar to the “memory” function on a calculator. Unlike most simple calculators, which have only a single memory location that holds one number, you can store many values at once in different variables. Also, the value stored in a variable is not limited to a single number, but can be an arbitrarily large amount of data. To keep track of the different variables, each one has a name.
SenseTalk provides three kinds of variables:
Names of local, global, and universal variables must begin with a letter or an underscore character
_. The name can be any length and can contain letters, digits, and underscores, plus many non-punctuation special characters. All variable names are case-insensitive (upper-and lower-case letters are treated as equivalent).
Some valid variable names:
Some invalid variable names:
3options -- variable names can't begin with a digit
ToBe?OrNot -- variable names can't contain punctuation or spaces
Local variables are the most common. They exist within the context of a single handler in a script. To create a local variable, you simply put something into it in a script. For example, the command
put 5 into foo will create the local variable
foo if it doesn’t already exist and store the number 5 in it.
Local variables cannot be accessed outside of the handler (or script) where they are used. References to
foo in another handler will be to a separate
foo that is local to that other handler. Local variables are temporary: their values go away when a handler finishes executing.
Parameters declared after the handler name in a
function declaration are a special type of local variable. Parameter variables are different from other local variables because when the handler begins executing they already contain values passed by the sender of the message. Other local variables have no initial value when the handler begins executing.
Local variables that have not been assigned a value (and that do not have a special predefined value, as described in Constants and Predefined Variables) will evaluate to their names. This provides a form of unquoted text string literal, which can be convenient in some instances, but might lead to confusion if you later choose to store something into a variable by that name. Generally, it is best to always use quotes around text literals to avoid any unexpected results.
Undefined Variables and the StrictVariables Global Property
Local variables that have not yet been assigned a value will ordinarily be treated as unquoted literals—in other words, their value is the same as their name:
put Hello -- Displays "Hello"
Sometimes this behavior can lead to trouble, such as if you inadvertently misspell the name of a variable later in the script and expect it to have the value previously stored in it. To help with debugging your script in such cases, or if you simply prefer a more rigorous approach, you can set
the strictVariables global property to true. When this property is set, any attempt to access a variable that has not been explicitly declared or assigned a value will throw an exception rather than returning the variable’s name:
put Bonjour into greeting -- Stores "Bonjour" in the variable greeting
set the strictVariables to true
put Bonjour into greeting2 -- Throws an exception
Some local variables have predefined values.
the strictVariables property does not affect the use of these values—you can continue to use them even though you have not explicitly assigned values to those variables (see Constants and Predefined Variables).
Global variables can be referenced from any handler within a project. Unlike local variables, global variables retain their value between different handlers. While local variables are undefined at the beginning of a handler each time that handler is called, global variables might already have a value that was assigned previously, either by the same handler (on an earlier call to it) or by a different handler.
To create and use global variables, they must be declared as global within each handler where they are used, so that SenseTalk can distinguish them from local variables. This is done using the
global keyword. The
global keyword can be used at the beginning of a line, like a command, followed by a list of the names of variables being declared as globals. This type of declaration must appear before any other use of those variables in the handler. Usually, therefore, it is good practice to place global declaration lines at the beginning of a handler, as in this example:
global didItBefore -- Declare the global variable
if didItBefore is true then -- Don't allow it to be done twice
answer "Can’t do it again!"
put true into didItBefore
It is also possible to refer to a global variable without declaring it in advance, by simply preceding its name with the
global keyword in any expression. Using this approach, our example could be rewritten like this:
if global didItBefore is true then
-- Don't allow it to be done twice
answer "Can’t do it again!"
put true into global didItBefore
Unlike local variables, global and universal variables that have not been assigned a value are simply empty—they don't evaluate to their names.
Because global variables are "global", they can be accessed from any handler in any script within a project. This provides a useful means of sharing information between different handlers. Care must be taken, however, not to use the same global variable name for different purposes in different parts of a project.
For example, if you used the
doSomethingUniquely handler above to keep an action from being performed twice, and then copied and pasted the same handler into a different script (changing only the
dotheThingToBeDone line) so that some other action would also be restricted to running just once, you would have a problem. Both scripts would now be using the same global variable (
didItBefore) to keep track of whether their action had already been performed, so the first one that calls its
doSomethingUniquely handler will prevent the other one from performing its action at all!
To solve this problem, you would need to use different global variables in each handler, by changing the variable names (
didTheOtherThingBefore, etc.) or come up with some other means of distinguishing between the two cases.
globalNames() function (or
the globalNames) can be used to get a list of the names of all global variables that have been assigned values.
Universal variables are created and used in exactly the same manner as global variables. The difference between global variables and universal variables is defined by the host application in which SenseTalk is running. Typically, universal variables have a broader scope than globals. For example, globals can exist within a single project while universals can allow information to be shared in common between different projects. Or, as is the case in Eggplant Functional, globals can have their values reset following each script execution while universals retain their values between runs during an entire session.
Universal variables must be declared using the
universal keyword, either on a separate declaration line sometime before they are referenced in each handler where they are used, or immediately before the variable name within any expression, in a manner identical to that for global variables.
universalNames() function (or
the universalNames) can be used to get a list of the names of all universal variables that have been assigned values. The following example will display the names and values of all universal variables:
repeat with each item of the universalNames
put "Universal " & it & " is " & value("universal " & it)
Variable Types Summary
In summary, there are three distinct types of variables that you can use in your scripts.
- Global and universal variables must be declared in each handler that uses them, or else preceded by the word
universaleach time they are used.
- Undeclared variables that are not preceded by the word
universalwithin a handler are local to that handler.
- Local variables have a value within a single execution of a single handler, and are discarded when the handler finishes executing.
- Global variables have a value that persists across handlers. They are discarded at the end of a run.
- Universal variables are similar to global variables, but typically have a larger scope as defined by the host application. For example, in Eggplant Functional, universal variables have a value that persists across handlers and across runs. They are discarded when Eggplant Functional quits.
The three types of variables are all distinct (that is, you can have local, global, and universal variables all in existence at the same time with the same name but different values).
Predefined variables (see Constants and Predefined Variables) are local variables which already have a value at the beginning of each handler. You can assign a different value to them in the handler and use them like any other local variable during that handler. But that value assignment will only apply in the current handler, and in other handlers they will still have their predefined value.
Suite variables are a special type of predefined variable in Eggplant Functional whose predefined values are stored permanently in a suite. See Creating and Using Suite Variables for more information.
Variables are created automatically by assigning a value to them. They can also be deleted, using the
delete variable command, or one of its variants.
delete [variable | local | global | universal] variableName
delete variable holder -- Makes local variable "holder" undefined again
delete local password
delete global accountNumber
delete universal pendingTasks
Metadata in Variables
In some cases, variables might contain extra information (also known as metadata) in addition to the ordinary value (the data) that they contain. For example, when a variable holds a date or time value, the actual data (the value) that is stored in the variable is a number that specifies an instant in time. In addition to this time value, the variable also holds a
format that specifies how the value should be presented to the user or represented when the value is requested as text (see Date and Time Values in SenseTalk).
As another example, when a variable holds a list, the list of values that it contains is the data (contents) of the container. The metadata in this case is the
currentIndex value that allows the list to be used as an iterator (see Ranges, Iterators, and Each Expressions).
In each of these cases, in addition to the data contents of the variable, SenseTalk makes the metadata accessible to the script as a property of the variable:
put the date into currentDate
put currentDate --> 10/22/10
put currentDate's format --> [mo]/[da]/[yr]
put "[year]" into the last 4 characters of currentDate's format
put currentDate's format --> [mo]/[da]/[year]
put currentDate --> 10/22/2010