Control Flow
Luwu's if statements and loops will look familiar if you've written Python, JavaScript or C. A block opens with a keyword like then or do and closes with end instead of braces or indentation.
Variables
local defines a variable that can be reassigned and const defines a binding that cannot be reassigned.
local lives = 3 -- a local can be reassigned
lives -= 1
const name = "Ada" -- a const can't
print(`{name} has {lives} lives left`)Ada has 2 lives left
A string in backticks is an interpolated string. Each {...} inside it is replaced by the value of the expression between the braces.
if statements
An if statement runs its block when the condition is true. elseif adds more conditions that are checked in order, and else runs when none of them matched.
const score = 72
if score >= 90 then
print("A")
elseif score >= 70 then
print("B")
else
print("Keep practicing")
endB
Values are compared with ==, <, >, <= and >=. Not equal is written ~= rather than !=. Conditions combine with the keywords and, or and not.
Truthiness
A condition doesn't have to be a boolean. false, nil and none count as false and every other value counts as true. That includes 0 and the empty string "" even though both count as false in Python and JavaScript.
if 0 then
print("0 counts as true")
end
if "" then
print("so does an empty string")
end0 counts as true so does an empty string
and and or give back one of their operands instead of true or false. a or b is a when a is truthy and b otherwise. That makes or the usual way to fall back to a default when a value is missing:
const nicknames: { [string]: string? } = { ada = "Countess" }
print(nicknames.ada or "stranger")
print(nicknames.grace or "stranger")Countess stranger
or return leaves the function when the value is falsy. or break and or continue do the same for loops:
const prices: { [string]: number? } = { apple = 1.25 }
const function price_of(fruit: string): string
const price = prices[fruit] or return `{fruit} isn't sold here`
return `{fruit} costs {price}`
end
print(price_of("apple"))
print(price_of("kiwi"))apple costs 1.25 kiwi isn't sold here
if expressions
An if statement runs statements. When you only need to pick a value, use an if expression. An if expression must always evaluate to a value. That's why it always has an else branch. Unlike an if statement, it doesn't end with end:
const health = 25
const status = if health > 50 then "healthy" elseif health > 0 then "hurt" else "down"
print(status)hurt
Loops
Counting with for
A numeric for loop counts from a start number to an end number with both ends included. An optional third number is the step, and a negative step counts down.
for i = 1, 3 do
print(i)
end
for i = 10, 0, -5 do
print(i)
end1 2 3 10 5 0
Looping over a table
To visit every item in a table, write the table after in. Each pass gives you a key and its value. In an array the key is the item's index and the first index is 1, not 0:
const fruits = { "apple", "kiwi", "pear" }
for index, fruit in fruits do
print(`{index}: {fruit}`)
end1: apple 2: kiwi 3: pear
Name a variable _ when you don't need it, as in for _, fruit in fruits do. You'll often see ipairs(fruits) or pairs(fruits) after in in Lua code. Both are deprecated in Luwu, and Tables explains how they differ from the plain loop.
while and repeat
A while loop checks its condition before each pass and stops once it's false:
local countdown = 3
while countdown > 0 do
print(countdown)
countdown -= 1
end
print("liftoff")3 2 1 liftoff
repeat ... until runs its body first and checks the condition afterwards. The body always runs at least once and the condition can read locals declared in the body:
const rolls = { 2, 5, 6, 3 }
local tries = 0
repeat
tries += 1
const roll = rolls[tries]
until roll == 6
print(`rolled a 6 on try {tries}`)rolled a 6 on try 3
break and continue
break leaves the loop right away. continue skips the rest of this pass and moves on to the next one. Lua doesn't have continue but Luau and Luwu do.
for i = 1, 10 do
if i % 2 == 0 then
continue
end
if i > 7 then
break
end
print(i)
end1 3 5 7
Scope
Luwu is lexically scoped. Where a variable can be used depends on where it's written in the source code and not on how the program runs. A local exists from the line that declares it to the end of its block, and the body of an if, a loop or a function is a block. Code inside a block can use the locals of every block around it:
const total = 12
if total > 10 then
const message = "that's a lot"
print(message)
end
-- `message` doesn't exist out herethat's a lot
Going further
Expressive Control Flow picks up where this page leaves off with if const, when chains, do expressions and or return. They let you get a value, check it and decide what to do with it in a single expression.