Skip to main content

Operators & Expressions

Arithmetic operators

OpNameExampleNotes
+additiona + b
-subtractiona - balso unary negation
*multiplicationa * b
/float divisiona / balways returns float
//floor divisiona // brounds toward -∞
%moduloa % ba % b == a - (a // b) * b
^exponentiationa ^ balways returns float
~bitwise NOT~aunary, 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)

OpNameExample
&ANDa & b
|ORa | b
~XORa ~ b
>>right shifta >> n
<<left shifta << 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 << -2 is equivalent to x >> 2.


Relational operators

OpMeaning
==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.0 is true)
  • Different types → always false (except integer/float coercion)
  • Tables, userdata, threads → compared by reference (identity, not structure)
  • nil only equals nil
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

OpMeaningBehavior
andlogical ANDReturns first falsy operand, or last operand
orlogical ORReturns first truthy operand, or last operand
notlogical NOTReturns 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 b fails if a is 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" .. 1 raises an error. Always tostring().


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. Use ipairs or explicit counting instead.


Operator precedence

Higher = tighter binding:

PriorityOpAssociativity
1 (highest)^right
2unary: not # - ~right
3* / // %left
4+ -left
5..right
6<< >>left
7&left
8~ (binary XOR)left
9|left
10< > <= >= ~= ==none
11andleft
12 (lowest)orleft
-- 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.