You can have Director execute different Lingo code in response to various conditions. Any non-zero expression (including negative numbers) is considered TRUE
, and only an expression that evaluates to zero is considered FALSE
. Refer to Chapter 5 for details on evaluating comparisons, including compound expressions. (These example multi-line code fragments must be placed in a handler for testing.)
The if
statement will execute different Lingo code based on the value of the specified expression. This allows you to, say, use a single Director movie on both Macintosh and Windows but branch to different code depending on the playback platform, as determined by the platform
property, such as:
if (the platform starts "Windows") then -- Do Windows-specific stuff here else -- Do Macintosh-specific stuff here end if
The if
statement has many possible forms, but I recommend only these. Items shown in curly braces are optional. Note the correct indentation:
The else if
and else
clauses are optional:
ifexpression
thenstatement1
{else ifexpression
thenstatement2}
{elsedefaultAction}
end if
For example:
if x = 1 then go frame "Slide1" else if x = 2 then go frame "Slide2" else if x = 3 then go frame "Slide3" else go frame "End" end if
The following forms are theoretically valid, but they often misbehave in Projectors and within nested if
statements, so I don’t recommend them:
ifexpression
thenstatement1
or
ifexpression
thenstatement1
elsestatement2
The one-line and two-line forms of the if
statement make it hard to tell if the indenting is correct even after Director auto-formats your Lingo.
Warning
Where I use the one-line form of if...then
in the examples throughout the book, I do so only for brevity. The Lingo compiler occasionally makes errors when evaluating one-line and two-line if
statements.
Use the following three-line form even for simple if
statements, especially when nesting if
statements.
if (expression
) thenstatement
end if
By always using an end if
statement, and by always including a carriage return after the then
keyword, Director won’t get confused and neither will you. The auto-indenting will work reliably and it also makes the code easier to read and debug. See Chapter 3.
You can nest if
statements to create the desired logic. It is crucial that you use the three-line if...end if
construct, rather than the one-line or two-line form. An end if
always pairs up with the most recent if
from the inside out. Let Lingo’s auto-indentation be your guide.
ifexpression1
then if expression2 thenaction1
elseaction2
end if elsedefaultAction
end if
Example 1-20 is a typical usage of a nested if
statement:
Although conceptually simple, the if statement consistently confuses new Lingo programmers. Avoid the common pitfalls shown in the following examples.
There must be one end if
for each if
statement. Watch for this, especially with nested ifs
, such as is shown in Example 1-21.
Example 1-21. Common If Statement Errors
if x > 5 then
if x < 7
statements
end if
-- You are is missing an "end if" here
If you omit the then
keyword, you’ll also have problems:
if x > 5 -- the keyword"then" is missing
statements
end if
Use one if...else if...end if
statement instead of a series of if
statements.
The following is inefficient because if x
equals 5, it will never equal 6, and vice versa:
if x = 5 then -- Do something end if if x = 6 then -- Do something different end if
This is more efficient (see also "Case Statements" later in this chapter):
if x = 5 then -- Do something else if x = 6 then -- Do something different end if
The incorrect order of comparison can lead to the wrong code being executed. Some code may never be executed, or code may be executed unintentionally.
In this example, both if
statements will be executed if x
equals 5. This may be what you want, but it is more likely a logic error:
if x > 0 thenstatements
end if if x > 4 thenstatements
end if
In this erroneous example, the second branch will never be executed because the first branch is taken in every case where the second condition would be TRUE
:
if x > 0 then
statements
else if x > 4 then
alternative statements (never reached)
end if
In this corrected example, the second branch will be executed only if x
is less than 4 but greater than 0:
if x > 4 then
statements
else if x > 0 then
alternative statements
end if
Nested if statements seem to give people fits. Don’t use a nested if
statement when an if...then...else if...end if
statement will suffice.
The innermost conditional clauses in this example are never executed.
Example 1-22. Nesting If Statements Properly
if x = 3 then
alert "Executed option 3"
-- This is never executed; if x is 3, it's not 4if x = 4 then
alert "Executed option 4"
-- This is never executed; if x is 4, it's not 5if x = 5 then
alert "Executed option 5"
end if
end if
end if
The correct construct is:
if x = 3 then
alert "Executed option 3"
else if x = 4 then
alert "Executed option 4"
else if x = 5 then
alert "Executed option 5"
end if
Use an end if
only for each if
, not for each else if
(sometimes Director won’t complain, but the results won’t be what you wanted). Example 1-23 is wrong.
Example 1-23. Using End If Improperly
if x = 3 then alert "Executed option 3" else if x = 4 then alert "Executed option 4" else if x = 5 then alert "Executed option 5" end if end if -- This is not needed end if -- This is not needed
Extraneous end if
s can change your logic unintentionally. Contrast the following with the earlier nested if
example. It will always execute the last alert
command because it follows the last end if
:
if field "name" <> EMPTY then -- These five lines of code are a nested "if". if length(field "name") > 10 then alert "Enter only the first ten letters" else alert welcome & field "name" end if -- This terminate the inner "if" statement end if -- This terminate the outer "if" statement -- This will always be executed alert "Please enter your name"
Each if
statement must have a matching end if
. Erroneous structures at the end of a preceding handler will trickle into the next handler and corrupt the indentation. Note the incorrect indentation in the mouseDown
handler caused by the missing end if
in the preceding mouseUp
handler:
on mouseUp if the clickOn = 3 then if rollover(7) then put "Yahoo!" end if put "whatever" -- This is missing an "end if" end on mouseDown put "Hello" -- Note incorrect indentation end
Note the corrected indentation of put "Hello"
in the mouseDown
handler:
on mouseUp
if the clickOn = 3 then
if rollover(7) then
put "Yahoo!"
end if
put "whatever"
end if -- That's better!
end
on mouseDown
put "Hello"
end
Look for ways to reduce the number of if
clauses. Here we’ve modified the example shown under "Multiple-Clause If...Then...Else If...Else...End If.” We’ve reduced the number of clauses by using the value of x
to construct the name of the destination marker (“Slide1,” “Slide2,” or “Slide3”).
if x >= 1 and x <= 3 then go frame ("Slide" & x) else go frame "End" end if
The case
statement conditionally executes Lingo statements based on the value of an item. It is often easier to implement than multiple if...then
statements, but long case
statements can be slower than the corresponding if...then
constructs. Director executes the statement(s) following the first value
that matches the case
clause. The colon after otherwise
is optional, and multiple statements can be included after each value to be matched. Once a match is found and its statements executed, subsequent values and their statements are ignored, and execution continues after the end case
statement.
case (item
)ofvalue1
:statement
value2
:statement
statement
value3
,value4
:statement
otherwise:statement
end case
Example 1-24 shows a case
statement and the equivalent if
statement.
Example 1-24. Case Statements
on keyDown case (the key) of RETURN: go frame "done" TAB, BACKSPACE: beep otherwise: pass end case end keyDown
The case
statement is equivalent to the following if ... then
statement:
on keyDown if (the key = RETURN) then go frame "done" else if (the key = TAB) or (the key = BACKSPACE) then beep else pass end if end keyDown
To use a comparative expression to branch within a case
statement, use TRUE
in the case
clause, and enclose the comparative expression in parentheses, such as:
on keyDown case (TRUE) of (the keyCode >= 123 and the keyCode <= 126): -- The user pressed an arrow key statements (the keyCode = 122): -- The user pressed F1 statements (the keyCode = 118): -- The user pressed F4 statements otherwise: alert "Please press an arrow key, F1 or F4" end case end keyDown
Repeat
loops repeat any statements within the body of the loop. They are used to cycle through a series of items, such as elements in a list, or to repeat an operation a specific number of times (they are equivalent to so-called for...next loops used in some languages). When the end repeat
command is reached, execution begins again at the top of the repeat
loop until some condition causes the loop to terminate. Execution continues at the statement following the end repeat
command. Use the Debugging window, described in Chapter 3, to examine the exact flow of Lingo as Director executes the steps in the repeat
loop.
Most repeat loops are very fast, even for hundreds or thousands of iterations, but Director can’t do anything else while you are executing a repeat loop, especially in Shockwave.
Warning
Don’t use repeat loops that monopolize Director’s attention for more than a few seconds.
In Shockwave, you can’t check whether an operation completed with netDone()
from within a repeat loop because Director doesn’t perform network operations during a repeat loop. Likewise, Director doesn’t update all system properties or update the Stage automatically during a repeat loop.
The repeat loop has four forms (3 forms of repeat with
plus repeat while
), as shown earlier in Table 1-3. The example multi-line code fragments must be placed in a handler for testing.
The repeat while
command repeats as long as an expression is TRUE
. If the expression never becomes FALSE, it will be an infinite loop.
Example 1-25. Repeat Loops
repeat while (the stillDown = TRUE) put "The mouse is still down" end repeat
The repeat with
commands loop through a range of values. Although not necessarily apparent, the three forms of the repeat with
loop all use an index variable (counter) that changes automatically each time the loop is executed.
In this example, the index variable (i
) starts at the initial value (in this case 1) and increments each time through the loop until it hits the upper bound (in this case 100). If the initial value is greater than the upper limit, the statement(s) within the loop are never executed.
repeat with i = 1 to 100 put "The next number is" && i end repeat
The following is the equivalent repeat while
loop to the above repeat with
loop. You can see that repeat with
loops are more convenient.
set i = 1 repeat while i <= 100 put "The next number is" && i set i = i + 1 end repeat
The repeat with...down to
command repeats for a decreasing range of values. In this case, the index variable (i
) is decremented (not incremented) each time through the loop.
repeat with i = 100 down to 1 put string(i) && "Bottles of beer on the wall..." end repeat
The repeat with...in
command cycles once through all the items in a list. (Refer to Chapter 6 or ignore this example for now.) Each time through the loop, i
is automatically set to the next item in the list. Use the following to loop through an irregular set of numbers:
set myList = [12, 17, 52, 43] repeat with i in myList put "The next item in the list is" && i end repeat
The variable i
is not an integer in the previous example; it is actually the contents of the next item in the list. The previous example can be simulated with a standard repeat with
loop, as follows:
set myList = [12, 17, 52, 43] repeat with j = 1 to count (myList) set i = getAt (myList , j) put "Item number:" && j put "The next item in the list is" && i end repeat
In the last example, note that the index variable j
is an integer and can be used to print a list element’s position within the list. You must manually intialize and increment an index variable to obtain a similar counter if using a repeat with...in
loop, such as:
set myList = [12, 17, 52, 43] set j = 1 repeat with i in myList put "Item number:" && j put "The next item in the list is" && i set j = j + 1 end repeat
Use next repeat
to skip the current iteration of a repeat
loop and to continue with the next iteration.
repeat with x = 1 to the number of members if the memberType of member x = 0 then next repeat end if put "Item" && x && "is type" && the memberType of member x end repeat
Use exit repeat
to exit the current repeat loop immediately. Program execution continues with the statement following the end repeat
statement. Exit repeat
exits only the current (innermost) repeat loop, and it will not exit nested repeat
loops. Use exit
, or abort
, or a flag to exit multiple loops, as shown in Example 1-26. (Again, use the Debugging window to examine the exact flow of Lingo as Director executes the following code.)
Example 1-26. Nested Repeat Loops
on findIt global gFoundIt set gFoundIt = FALSE -- Search for a #shape cost member repeat with y = 1 to the number of castLibs repeat with x = 1 to the number of members of castLib y set thisItem = the memberType of member x of castLib y if thisItem = #shape then set gFoundIt = member x of castLib y exit repeat -- exit the innermost loop end if end repeat -- exit the outermost loop too if gFoundIt then exit repeat end if end repeat -- Execution continues here after loop if gFoundIt then put "Found shape cast member at" && gFoundIt else put "Shape cast member not found." end if end
Lingo does not precalculate the number of iterations it will perform for a repeat...with
loop. Rather, it reevaluates the expression each time through the loop. In the following example, we manually increment the index variable (i
) to step by two rather than one. Note that we add only 1 to i
, not 2, because Lingo will automatically increment i
once each time the loop is executed.
Example 1-27. Customized Repeat Loops
on printEvenNumbers repeat with i = 0 to 100 put i set i = i + 1 end repeat end printEvenNumbers
Tip
Avoid manually setting the index variable within a repeat
loop unless you need to change the number of loop iterations. Setting it incorrectly can lead to an infinite loop.
After a loop completes, the index normally is one greater than the ending value:
on testRepeat repeat with i = 1 to 100 put i end repeat put "The ending value for i is" && i end testRepeat testRepeat -- 1 -- 2 -- <etc.> -- 99 -- 100 -- "The ending value for i is 101"
An infinite loop is a repeat
loop that will never be exited because the conditional expression never turns FALSE
. (Apple’s street address in Cupertino, California, is One Infinite Loop). An infinite loop will appear to hang the computer, and you must abort the Projector or halt the movie to stop it.
The most simple infinite loop is shown in Example 1-28.
Unless you add an exit repeat
, Lingo will never exit such a repeat
loop:
startTimer repeat while TRUE if the timer > 60 then exit repeat else -- do something end if end repeat
But this would be better written as:
startTimer repeat while the timer <= 60 -- do something end repeat
It is easy enough to create an infinite loop accidentally. The following will loop forever, assuming the loop takes less than 60 ticks to execute, because startTimer
is within the repeat
loop and keeps resetting the timer.
startTimer repeat while the timer <= 60 startTimer -- do something end repeat
The following would lead to an infinite loop as well. The variable x
is unintentionally set to 5; the programmer did not realize that x
is also being used as the loop’s index variable.
repeat with x = 1 to 10 put "x" && x set x = 5 end repeat
A loop will also be infinite if some condition you expect to become FALSE
remains TRUE
forever. Suppose you are waiting for a sound to start:
puppetSound "mySound" repeat while not soundBusy(1) nothing end repeat
If the sound never starts (in this case, you need to add updateStage
after the puppetSound
command), Director will loop forever because soundBusy(1)
will never become TRUE, so not soundBusy(1)
will always remain FALSE
.
Tip
Use the Debugger to diagnose infinite loops and similar problems. See Chapter 3.
Get Lingo in a Nutshell now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.