Variables, Operators, and Control Flow
Local, global, and property variables; Lingo operators and precedence; if, case, and repeat forms.
Variable kinds and scope
| Kind | Declared with | Lifetime | Visible to |
|---|---|---|---|
| Local | First assignment | One handler invocation | That handler only |
| Global | global gName | Entire player session, across movie branches | Every handler that declares the same global |
| Property | property pName | Life of the script instance / child object | Handlers of that instance (and via the pName of obj) |
global gScore
on prepareMovie
gScore = 0 -- initialize globals early
end
property pSpeed -- per-instance state in a behavior/parent script
on new me, aSpeed
pSpeed = aSpeed
return me
endKey semantics:
- A variable used before assignment raises the classic error "Variable used before assigned a value". In practice this error usually means a missing
thebefore a system property name, or a typo. globalmust be declared in every handler (or once at script top) that touches the global. Undeclared identifiers become locals.- Globals survive
go to movie; they are only reset byclearGlobals()or player restart.clearGlobals()also clearsthe actorListin some player versions, a classic compatibility trap. - Property variables on behaviors are per sprite instance; two sprites sharing a behavior get independent copies.
showGlobals()andshowLocals()print state to the Message window.
Assignment forms
All of these assign; all appear in real code:
set x = 5
set x to 5
put 5 into x
x = 5put ... after and put ... before are string append/prepend operators, not general assignment:
s = "world"
put "hello " before s -- "hello world"
put "!" after s -- "hello world!"Operators
Precedence from highest to lowest (operators on one row bind equally, left to right):
| Level | Operators |
|---|---|
| 1 | ( ) parentheses |
| 2 | unary -, not |
| 3 | *, /, mod |
| 4 | +, - |
| 5 | &, && (string concatenation; && inserts a space) |
| 6 | =, <>, <, <=, >, >=, contains, starts |
| 7 | and |
| 8 | or |
Details that matter:
=is comparison in expressions and assignment in statements; there is no==.<>is "not equal".- Integer division truncates:
5 / 2is2;5.0 / 2is2.5. Mixed integer/float arithmetic promotes to float. modkeeps the sign of the left operand:-7 mod 3is-1.containsandstartsare case-insensitive string tests (diacritic-insensitive too, per the documented string comparison rules).and/orevaluate both operands (no short-circuit) in classic Lingo. Do not portif voidP(x) or x.count = 0literally to a short-circuit language without noting that Lingo evaluated (and errored on) the second term.&coerces numbers to strings:"score: " & 10is"score: 10".- String comparison with
=,<etc. is case-insensitive.
Conditionals
if x > 5 then
put "big"
else if x = 5 then
put "exact"
else
put "small"
end if
-- single-line form (no end if)
if x > 5 then put "big"
-- single-line with else
if x > 5 then put "big"
else put "small"case compares one expression against candidate values (with optional multi-value lines and otherwise):
case the key of
"a", "A": doLeft
"d", "D": doRight
RETURN:
submitForm
beep
otherwise: nothing
end caseLoops
repeat with i = 1 to 10 -- inclusive both ends, 1-based convention
put i
end repeat
repeat with i = 10 down to 1 -- descending
put i
end repeat
repeat with x in someList -- iterate list VALUES
put x
end repeat
repeat while soundBusy(1) -- condition loop
nothing
end repeatFlow control inside loops:
exit repeatbreaks the innermost loop.next repeatcontinues to the next iteration.exitleaves the whole handler.
Blocking loops block everything. Lingo is single-threaded and cooperative. A repeat while loop freezes rendering, input, network callbacks, and sound cueing until it exits. Old code uses tight repeat loops only for sub-second waits; anything longer is done by looping the playback head on a frame (go to the frame) and testing a condition each frame.
Calling conventions
result = myFunction(a, b) -- parentheses required when using the return value
myCommand a, b -- command form, no return value used
sprite(3).myHandler(1) -- dot-syntax call on an object/behavior
call(#myHandler, obj, 1) -- send to a specific script instance
do "x = x + 1" -- compile and execute a string at runtimethe result holds the return value of the most recent handler call made without capturing it, a frequent idiom in Director 4-era code:
doCalc 5
answer = the result