The LiveCode scripting language, is a full-featured programming language with all the constructs of Java, C, and other common procedural programming languages. This reading will explain how LiveCode implements these basic constructs. Those who have experience with programming languages will recognize the similarities and differences.
By the end of this reading you should be able to answer the following questions as they apply to LiveCode:
Constants and Literals
,. Understand the differences in how these operators concatenate text strings.
Containers. Sometimes you may hear the term container used in LiveCode. A container is a storage location that has a name and can hold a value, such as a number or a string of characters. For instance, a LiveCode field has a name, and it can hold values or data, and so is a container. Using this definition, a variable is also a container. A variable is similar to a field in that it is a container for data, but it differs in that a field has a visible presence on the card, whereas a variable exists only in the computer’s memory. Thus the term container in LiveCode can refer to both variables and fields. Another way to think of it is that variables and fields are examples of a general class of things that are containers.
A variable called holder
with value "Hello world"
Virtually all programming languages make use of variables, and LiveCode is no exception. Variables are indispensable tools in programming, because they provide a way to store some value or information in memory until a handler needs access to it.
The concept of variables is not a difficult one—a variable is simply a named container that can hold a value. You can visualize a variable as a box in the computer’s memory with a name on it. The box can hold information, which can be referenced by its name. The box can hold any kind of data or information you need it to: strings of text, numbers, true/false values, even binary data.
There are a few simple rules for naming LiveCode variables. A variable name:
Creating Variables. In many programming languages you have to formally declare a variable and specify what type of data it can hold. Creating variables in LiveCode is a snap—you simply refer to it in a put statement:
put "stuff" into holder
Here’s a breakdown of what each term in this statement does:
put– The put command works for putting values into variables as well as fields
"stuff"– This can be whatever value you wish the variable to contain—text, numbers, true/false, etc.
into– Means the value will completely replace the value contained in the variable. There are other terms (
after) you can use if you want to append the value to what is already in the variable.
holder– A variable with this name is created if it doesn't already exist, and the value, "stuff" in this case, is put into it. From then on you may refer to the variable by this name.
If you script it like this, the last word in the put statement—holder, in this example—will become a variable, and it will hold the value of the second word of the statement—"stuff".
Variables exist as soon as they are used as a variable. The first time you state the name of a variable in a put statement, the virtual box or container with that name is created. Once the variable has been created, you can use the name to put a value into the variable. You can also use the name to put the value the variable contains somewhere else.
put 10 into myNumber put myNumber + 5 into field "sum"
Think of a variable this way: You’ve seen and used a trash can. It’s a container for things. Let’s create an imaginary trash can and call it "Oscar" (indulge me). If you put a newspaper into the trash can, the newspaper is still a newspaper. You can look inside the can and identify its contents as a newspaper. You can reach inside the can and pull out the newspaper and replace it with an apple core. Oscar now contains an apple core (which retains its identity as an apple core). If you place the newspaper into a different trash can called "Felix", it is still a newspaper. Throughout all this, the trash cans retain their names and you can still refer to them as Oscar or Felix (an odd couple), since the trash cans never lose their names or identities as containers even when their contents may change. At the end of our example, then, Oscar is holding an apple core and Felix is holding a newspaper (so apropos).
It’s the same way with a variable. If you have a variable and you name it holder for example, then you put "3" into that variable, the variable holder is just a container and inside it is the value 3. Putting 3 into the variable doesn’t change the value or nature of the 3 and it doesn’t change the variable’s name.
The term scope refers to where a variable and its value are recognized. Persistence refers to whether or not the variable and its value are preserved after a handler runs. Variables created inside a handler with the
put command exist only while the handler in which it was created is executing. As soon as the handler finishes running, the variable and the value it contains disappear. That is, its
scope is local to the handler and its persistence is temporary. The next time the handler is executed, the variable is created all over again, and it does not retain its value from the previous time the handler was executed. We refer to variables like this as temporary, or handler local variables. In the example below myNumber is a temporary, handler local variable:
put 10 into myNumber put myNumber + 5 into field "sum"
Variable Scope—Handler-only, Local, or Global. Often you may want the value contained in a variable to persist beyond the scope of just a single handler. In order for a variable and its value to persist longer than the life of the handler, it must be declared as as either a global variable or a script local variable. Once created, these types of variables and their contents are retained after a handler has finished running.
Script local variables are accessible from any handler in the script where they are declared. Simply include this statement outside of all handlers in a script:
local someLocalVar on handler1 --do some stuff put "hello" into someLocalVar end handler1 on handler2 --do some other stuff put someLocalVar into field "result" end handler2
Once declared in the script, this variable and its value are accessible from any handler in the script. In the example above the value of
someLocalVar is accessible between both
handler1 runs first,
handler2 will put the text "hello" into the field.
Variable Scope—Global Variables. Global variables can be accessed anywhere in the stack where they are declared. Unlike a variable used only inside one handler, a global variable retains its value even after the execution of the handler that created it. Just as declaring a script local variable, declaring a global variable is simple:
A global variable must be declared and identified as such in every script that uses that global variable. Otherwise, the handlers that use the variable name will instead create temporary handler-only variables with the same name. For example, let’s say we have a field "start" with the number 12 in it. Button 1 has the following script:
global holder on mouseUp put field "start" into holder end mouseUp
Here is the script of Button 2:
on handler2 add 6 to holder put holder into field "result" end handler2
When Button 1 is clicked, the global variable holder is given the value of 12. This value is then accessible to all handlers in that script, and in any script where global holder is declared. Thus, after Button 2 is clicked (assuming Button 1 was clicked first) the value of holder, and of field "result", becomes 18.
Variable Scope—Handler-local Variables. Contrast this to the case where no global variable is declared. So the script of Button 1 would be:
on mouseUp put 12 into holder end mouseUp
Button 2’s script would be:
on mouseUp add 6 to holder put holder into field "result" end handler2
In this case, holder has a value of 12 while Button 1’s mouseUp handler is running. But holder has a value of 6 after you click Button 2 (because it is adding 6 to nothing.) Unless the variable is declared as global (or local) outside of the handlers the variable and its value are temporary and limited in scope to the handler in which it was created.
Local and Global Variables inside a Handler. It is also possible to declare local and global variables inside a handler within a particular script. This would make the variable accessible only to the handlers in which the local or global variable is declared. For example:
on mouseDown global holder put 12 into holder end mouseDown on mouseUp add 6 to holder put holder into field "result" end mouseUp
In this case, the global variable holder is available only to mouseDown (and any other script or handler in the stack that declare
holder as global.) It is not available to mouseUp.
Both local and global variables and and their values disappear when the stack is closed and removed from memory. So the variable and its value would not persist if you quit LiveCode and restarted it, for example.
The LiveCode keyword
it is a special-purpose variable that holds the results of the
get command (and several other commands you’ll learn about later). It can help to make scripts more readable. However, you need to be careful, because the
it variable doesn’t work the same as the pronoun "it" in English; that is,
it doesn’t know what its antecedent is simply from context. You have to make sure something is in
it before referring to
it. For example:
if there is a button "clickme" then put it into field "results" end if
if there is a button "clickme" then get the label of button "clickme" put it into field "results end if
A constant is a named container, similar to a variable. However, as the term implies, the value of a constant is fixed and cannot be changed. Some constants make it fast and easy to refer to certain characters or values that are commonly used. Others simply provide enhanced readability in scripts.
Text constants: LiveCode defines several text constants to provide special characters that cannot readily be typed in directly.
spacecan enhance readability of a statement in a handler.
Other constants: A number of other constants represent numeric and mathematical values, and can be used for convenience and readability:
Remember that these constants are not literal strings; they stand for their values, and so can be used as if those literal values had been typed into the command.
A literal is something that is the value itself. In LiveCode scripting, anything enclosed in double quotes is treated as a literal string; that is, the string inside the quotes is just what it is. This seems almost too obvious to discuss, but it is an important thing to understand, because of a quirk of LiveCode.
The use of quote marks becomes extremely important in keeping literals distinguished from variables. In LiveCode an unquoted string that has never been used as variable often—but not always—functions like a literal string. This can cause considerable confusion. Look at this handler, for example:
on mouseUp show image flower end mouseUp
LiveCode, attempting to be helpful, will try to figure out what the word ‘flower’ is. Since you have never used it as a variable, LiveCode will assume you meant it to be a literal value, and show the image object named "flower", if there is one. This might be alright and never cause a problem.
But what if your handler became much longer, and the
show image statement was joined by many others? Then, months later, you come back and decide you need a variable at the top of your handler for some other reason. You decide that 'flower' makes a good variable name so you do this:
on mouseUp put "petunia" into flower -- in the meantime, you have placed -- lots more commands here, and you forgot -- that you had this statement: show image flower end mouseUp
Now, suddenly, your handler that was reliably showing an image named "flower" is suddenly showing an image named "petunia", or more likely, producing an error because there isn’t any image named "petunia"! It is a good practice to always use quotes around the names of all objects when referring to them by their names, to avoid problems like this one.
Now let's consider the opposite situation, where you put quote marks where you don't intend them. Look at this handler:
on mouseUp put "flower" into thisImage show image thisImage end mouseUp
This would take the literal string "flower" and place it within a variable called "thisImage." In referencing the variable on the very next line, the handler actually looks at the contents of the variable. Therefore, the handler would display an image called "flower." However, the handler would operate differently if one line were changed slightly:
on mouseUp put "flower" into thisImage show image "thisImage" end mouseUp
Here the second command of the handler would try to display an image called "thisImage" since enclosing thisImage within quotation marks indicates that it is to be treated as a literal and not as a variable. Details matter!
Operator: An operator creates a relationship between the element on its left and the element on its right. You are probably most familiar with arithmetic operators. The symbols LiveCode uses as arithmetic operators are:
The rules of mathematics establish a standard order in which operations should be performed when there is more than one operator in a single statement. LiveCode follows the standard order of precedence in arithmetic operators you learned in algebra:
As in algebra, parentheses can be used to override default precedence.
Some operators are keywords rather than symbols:
put 25 div 8 into myNumber
This divides 25 by 8 and puts the result of 3 into the variable myNumber. The remainder of 1 is simply ignored.
put 25 mod 8 into myNumber
This divides 25 by 8 and puts the remainder of 1 into the variable myNumber. The rest of the answer is simply ignored.
We will see other types of operators later.
Commands are directives that usually result in some action being taken. Since LiveCode scripting is based on a human language, English, virtually all commands are in the form of verbs. We have already seen a few commands:
beep. There are many more built-in commands in LiveCode, which are described and documented in the LiveCode Dictionary. Let’s take a closer look at a handful of commands.
put command is used to put values into containers. We have used this to put various strings into a field. We’ve also seen that it works essentially the same for variables. In this regard it is considered LiveCode’s assignment statement. The key words
before determine how the new value affects the existing contents of the container.
on mouseUp put "Eeyore" into hundredAcreWood put "Pooh Bear" into hundredAcreWood end mouseUp
This handler will take the literal string "Eeyore" and place it into the variable hundredAcreWood. Then it will place the another literal string "Pooh Bear" into the same variable, replacing the previous contents completely ("Typical," as Eeyore would grumble).
on mouseUp put "Eeyore" into hundredAcreWood put "Pooh Bear" after hundredAcreWood end mouseUp
This handler will place the literal string "Pooh Bear" directly after the string already residing within the variable, resulting in "EeyorePooh Bear" contained within hundredAcreWood (genetic engineering gone awry).
on mouseUp put "Eeyore" into hundredAcreWood put "Pooh Bear" before hundredAcreWood end mouseUp
This handler will place the literal string "Pooh Bear" directly before the string already residing within the variable, resulting in "Pooh BearEeyore" contained within hundredAcreWood (more threatening even than a heffalump or woozle).
So far we have always specified a destination for our
put command. It is also permissible to use
put without a destination, like this:
put "Hello World"
When you use
put without a desination container designated after
before, LiveCode will display the result in the Message Box. This can serve as a quick and easy way of checking the value of a variable or the result of a put statement.
Techie note: The message box is what other programming environments often refer to as the standard output; that is, where the output of a command goes when there is no destination specified.
Arithmetic Commands: LiveCode provides four commands for common arithmetic calculations:
These commands perform the calculation on the value within the container and replace the value with the answer. For instance, these are all valid LiveCode statements:
add 5 to field "value" subtract 10 from myvariable multiply myvariable by 2 divide field "value" by 16
Few programming languages have arithmetic commands like these. Instead, they accomplish the same result with an assignment statement that references the variable in the calculation and assigns the result to the same variable. This technique also works in LiveCode. So you could do the same thing as above like this:
put field "value" + 5 into field "value" put myvariable - 10 into myvariable put myvariable * 2 into myvariable put field "value" / 16 into field "value"
As you can see, in many cases the arithmetic commands make the statements shorter and easier to read.
A function takes some input, performs a predefined process on the input value and returns a modified value. Functions are always used within the context of a larger statement, never by themselves. A function can be used anywhere the value it returns is appropriate.
Forms: LiveCode functions generally have two forms:
put sqrt(25) into field "answer"
put the sqrt of 25 into field "answer"
Argument: An argument is the input value that the function operates on. Most (but not all) functions require at least one argument. In the example given above (
sqrt(25)), the argument is
25. Arguments may be specified explicitly (as above) but can also come from a variable or a field or other source of value. For example, to find the absolute value of a number stored in a variable using the
on mouseUp global myNum put abs(myNum) into field "Result" end mouseUp
In this example, the argument passed to the
abs() function is a variable. The function will perform its operations on the contents of the variable and place the result in a certain field. Obviously, the arguments passed to a function can vary and the values the function returns are dependent upon the arguments passed.
Here are some other useful functions. Remember that functions have two different forms.
Here are two functions we’ve already seen. These functions don’t need an argument, since they simply get the information they need from the operating system. Note that they can use either form, but the “prose” form is the most common, as it is somewhat easier to read.
random: This is a function that can often be used in instructional applications to provide variety and unpredictability. It returns a random value between 1 and the argument, inclusive. For example:on mouseUp put random(20) into nextQuestion end mouseUp
This handler would then put into nextQuestion any number between 1 and 20, the lowest possible value being 1, and the highest possible value being 20.
round: Rounds a number up or down according to standard rounding rules.put the round of 36.4 -- yields 36 put round(36.446,2) -- rounds to two decimal places; yields 36.45
date: Returns the current date as set by the operating system.put the date
time: returns the current time as set by the operating system.put the time put time()
We will see many more functions later. You are welcome to explore and experiment with some of them. They are always identified as functions in the LiveCode Language Dictionary.
Concatenation means ‘linking things together’. In LiveCode the primary concatenation operator is the ampersand (
&). It can be used in conjunction with a
put statement to append one chunk of text to another.
put "This" & "is" & "my" & "stack" into myStack
This results in a string "Thisismystack" being placed in the variable myStack.
put "This" && "is" && "my" && "stack" into myStack
This results in a string "This is my stack" being placed in the variable myStack.
The comma (
,) is a special concatenation symbol in LiveCode. It appends pieces of text or numbers together, separating them by a comma. For example:/p>
on mouseUp put "Eeyore","Pooh Bear" into hundredAcreWood end mouseUp
This handler places the two strings together with a comma separating them (resulting in
Eeyore,Pooh Bear) into a variable. This operator is an effective tool for concatenating several strings into a single comma-delimited string.
Of course, just concatenating literal strings together makes little sense. After all, you can more easily just put them into the same string to begin with. The real power of concatenation lies in the ability to combine literal strings with variable values to create more “dynamic” texts strings. For example, let’s say we want to have a field on all of the cards in our stack that reports which card you are on. You might put a handler similar to this in the stack script:
on openCard put the number of this card into currentCard put the number of cards into totalCards put "Card" && currentCard && "of" && totalCards \ & "." into field "counter" end openCard
You will rapidly see how useful concatenation operators can be.
As long as we are talking about special symbols, let’s look at the
\ symbol. This is a special symbol that functions as a line continuation character in the LiveCode script editor. If a line is too long to fit conveniently in the script editor window, you can use the
\ character to break it into two or more lines for easier viewing. You’ll often see this character used in these lessons to keep lines in example code to a reasonable length. A line split with
\ is treated like a single line when a script is executed.
put "A very, very, very, very long sentence." \ into field "myField"
Note, however, that a
\ character inside a quoted literal string does not break the line, because it is considered part of the quoted string. If you want to break a line inside the quoted string, you have to break the quote up into two parts and concatenate the two parts, like this:
put "This is much, much, much, much longer" \ & " than the other one." into field "myField"