Operators & Expressions
Arithmetic operators
| Op | Name | Example | Notes |
|---|---|---|---|
+ | addition | a + b | |
- | subtraction | a - b | also unary negation |
* | multiplication | a * b | |
/ | float division | a / b | always returns float |
// | floor division | a // b | rounds toward -∞ |
% | modulo | a % b | a % b == a - (a // b) * b |
^ | exponentiation | a ^ b | always returns float |
~ | bitwise NOT | ~a | unary, NOT negation |
Division behavior
print(10 / 3) -- 3.3333... (float)
print(10 // 3) -- 3 (integer)
print(-10 // 3) -- -4 (floor toward -∞)
print(10.0 // 3) -- 3.0 (float floor)
Modulo
print(10 % 3) -- 1
print(-10 % 3) -- 2 (result has sign of second operand)
Bitwise operators (integers only)
| Op | Name | Example |
|---|---|---|
& | AND | a & b |
| | OR | a | b |
~ | XOR | a ~ b |
>> | right shift | a >> n |
<< | left shift | a << n |
~ | NOT (unary) | ~a |
print(0xff & 0x0f) -- 15 (0x0f)
print(0x01 << 4) -- 16
print(0xff >> 4) -- 15
print(~0) -- -1 (all bits set)
[!tip] Shift amounts can be negative
x << -2is equivalent tox >> 2.
Relational operators
| Op | Meaning |
|---|---|
== | equal |
~= | not equal |
< | less than |
> | greater than |
<= | less or equal |
>= | greater or equal |
Rules
- Same type → compare values (integers and floats compare by value:
1 == 1.0istrue) - Different types → always false (except integer/float coercion)
- Tables, userdata, threads → compared by reference (identity, not structure)
nilonly equalsnil
print(1 == 1.0) -- true (numeric comparison)
print("1" == 1) -- false (different types)
print({} == {}) -- false (different tables)
local t = {}
print(t == t) -- true (same reference)
Logical operators
| Op | Meaning | Behavior |
|---|---|---|
and | logical AND | Returns first falsy operand, or last operand |
or | logical OR | Returns first truthy operand, or last operand |
not | logical NOT | Returns true or false |
-- Short-circuit evaluation
print(nil and "hi") -- nil
print(false and "hi") -- false
print("a" and "hi") -- "hi"
print(nil or "hi") -- "hi"
print(false or "hi") -- "hi"
print("a" or "hi") -- "a"
-- Idioms
local x = v or default -- default if v is nil/false
local max = (a > b) and a or b -- ternary-ish (caution: fails if a is falsy)
[!warning] Ternary idiom trap
(cond) and a or bfails ifais falsy. Use if/else for safety.
Concatenation
local s = "hello" .. " " .. "world" -- "hello world"
local n = "value: " .. 42 -- error in 5.4! Use tostring()
local ok = "value: " .. tostring(42) -- "value: 42"
[!important] No implicit number→string in 5.4
"x" .. 1raises an error. Alwaystostring().
Length operator
#s -- string length (bytes)
#t -- table length (border of sequence)
For tables, #t returns the border: the index i such that t[i] is not nil and t[i+1] is nil.
print(#"hello") -- 5
print(#{10, 20, 30}) -- 3
print(#{1, nil, 3}) -- 1 or 3 (undefined!)
[!warning] Non-sequences
#on tables with gaps (nil holes) is undefined. Useipairsor explicit counting instead.
Operator precedence
Higher = tighter binding:
| Priority | Op | Associativity |
|---|---|---|
| 1 (highest) | ^ | right |
| 2 | unary: not # - ~ | right |
| 3 | * / // % | left |
| 4 | + - | left |
| 5 | .. | right |
| 6 | << >> | left |
| 7 | & | left |
| 8 | ~ (binary XOR) | left |
| 9 | | | left |
| 10 | < > <= >= ~= == | none |
| 11 | and | left |
| 12 (lowest) | or | left |
-- Precedence examples
a + b * c -- a + (b * c)
a ^ b ^ c -- a ^ (b ^ c) -- right assoc
a .. b .. c -- a .. (b .. c) -- right assoc
not a == b -- (not a) == b
a and b or c -- (a and b) or c
Expressions
Parenthesized
(a + b) * c
Function calls
f()
f(a, b)
t:m()
Varargs expression
... -- expands to all variable arguments
Table constructors
{1, 2, 3}
{x = 1, y = 2}
{[f(1)] = g; "x", "y"}
See Tables for details.