Lua Expressions

This post will walk you through what Lua expressions are, the types of expressions, operator precedence, and best practices.


What Is an Expression in Lua?

In Lua, an expression is a piece of code that evaluates to a value. You can use expressions to assign values, control flow, or compute data.

Examples of Lua expressions:

2 + 3         --> 5
"a" .. "b"    --> "ab"
true and false --> false
x * y + 1     --> evaluates based on x and y

Anything that results in a value—whether a number, string, boolean, table, or function—is considered an expression.


Types of Lua Expressions

Lua supports a rich set of expression types:

1. Literals

Basic values like:

42         -- number
"hello"    -- string
true, false -- boolean
nil        -- absence of value

2. Variables

Refers to named storage locations:

local x = 5   -- x is a variable; '5' is a literal expression

3. Arithmetic Expressions

+  -  *  /  %  ^  -- standard arithmetic operations

Example:

(2 + 3) * 4   --> 20

4. Relational Expressions

Return a boolean result:

== ~= < > <= >=
5 < 10     --> true
"a" == "a" --> true

5. Logical Expressions

Used for conditional evaluation:

and  or  not
true and false --> false
not true       --> false

Lua uses short-circuit evaluation:

  • a and b evaluates b only if a is truthy.
  • a or b evaluates b only if a is falsy.
x = nil or 5   --> x = 5

6. Concatenation

Use .. to concatenate strings:

"foo" .. "bar" --> "foobar"

7. Table Constructors

Used to create tables (Lua’s only data structure):

{}                        -- empty table
{1, 2, 3}                 -- array-like table
{name = "Lua", ver = 5.4} -- dictionary-like table

8. Function Calls

You can call:

  • Global functions (print("hello"))
  • Table fields (table.insert(t, val))
  • Anonymous functions ((function() return 5 end)())
function add(a, b) return a + b end
x = add(2, 3) --> 5

9. Anonymous Functions (Lambdas)

Lua supports inline function expressions:

square = function(x) return x * x end
print(square(4)) --> 16

10. Parenthesized Expressions

Used for grouping:

(2 + 3) * 4 --> 20

Also useful for forcing single values from multi-return functions:

function multi() return 1, 2 end
x = (multi())  --> x = 1; only first value is returned

Operator Precedence in Lua

Understanding precedence is crucial to avoid bugs.

Precedence Operators Description
1 (highest) ^ Exponentiation
2 not - (unary) # Logical not, unary minus, length
3 * / % Multiplication, division, modulo
4 + - Addition, subtraction
5 .. String concatenation
6 < > <= >= == ~= Comparisons
7 (lowest) and Logical AND
8 or Logical OR

Note: .. (concatenation) is right-associative, as is ^ (exponentiation).

2 ^ 3 ^ 2 --> 2 ^ (3 ^ 2) = 512
"a" .. "b" .. "c" --> "abc"

Use parentheses to ensure clarity:

(2 + 3) * 4 ~= 2 + (3 * 4)

Expression Evaluation Rules

  • Truthiness: Only false and nil are falsy. Everything else (including 0 and empty strings) is truthy.
  • Multiple Returns: A function returning multiple values behaves differently depending on context.
function f() return 1, 2 end
x = f()          --> x = 1
x, y = f()       --> x = 1, y = 2
print(f())       --> prints 1 2
print((f()))     --> prints 1

Common Pitfalls

  1. Confusing == and =:

    • = is assignment.
    • == checks equality.
  2. Misunderstanding operator precedence:

 print(2 + 3 * 4) --> 14, not 20
  1. Using .. on non-strings without conversion:
print("The value is: " .. 123) --> Works
print("Value: " .. nil)        --> Error!

Convert explicitly:

print("Value: " .. tostring(nil)) --> "Value: nil"
  1. Wrong assumptions about truthiness:
if 0 then print("yes") end --> prints "yes"

Best Practices

  • Always use parentheses when unsure about precedence.
  • Prefer local variables for clarity and performance.
  • Avoid using nil in expressions unless intended.
  • Use tostring() when concatenating mixed types.