---
url: /programming-fundamentals/operators-and-logic.md
description: >-
  Arithmetic, comparisons, boolean logic, and truthiness rules that surprise
  beginners.
---

# Operators and Logic

*Written: {{ $frontmatter.date }}*

## Learning objectives

* You do arithmetic with `+`, `-`, `*`, `/`, `//`, `%`, `^`, and unary `-`.
* You join strings with `..` and measure length with `#`.
* You compare values and explain what a boolean result means.
* You combine conditions with `and`, `or`, and `not`.
* You predict truthiness and convert with `tonumber` and `tostring`.

## Prerequisites

* Read [First Script](../getting-started/first-script.md). You can run a Script and read output.
* Read [Variables and Values](variables-and-values.md). You create variables with `local` and print them.

## Arithmetic operators

[operators](https://create.roblox.com/docs/luau/operators) are symbols that compute new values. Arithmetic operators compute with [numbers](https://create.roblox.com/docs/luau/numbers). Luau gives you eight: `+` adds, `-` subtracts, `*` multiplies, `/` divides, `//` divides and rounds down, `%` gives the remainder, `^` raises to a power, and a unary `-` in front of one value negates it.

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local apples = 10 + 4
local eaten = 10 - 4
local boxes = 3 * 4
local shared = 10 / 4
print(apples)
print(eaten)
print(boxes)
print(shared)
```

```txt
14
6
12
2.5
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 adds `10 + 4` and stores `14` in `apples`.
3. Line 3 subtracts `10 - 4` and stores `6` in `eaten`.
4. Line 4 multiplies `3 * 4` and stores `12` in `boxes`.
5. Line 5 divides `10 / 4` and stores `2.5` in `shared`. Division keeps decimals.
6. Lines 6 to 9 print all four results in order.

Three operators surprise beginners. `//` is floor division: it divides, then rounds down toward negative infinity. `%` is the remainder after division. `^` is a power, not multiplication.

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local fullTeams = 10 // 4
local leftOver = 10 % 4
local squared = 3 ^ 2
local flipped = -squared
print(fullTeams)
print(leftOver)
print(squared)
print(flipped)
```

```txt
2
2
9
-9
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 computes `10 // 4`. Plain division gives `2.5`, and flooring gives `2`.
3. Line 3 computes `10 % 4`. Four fits twice into ten with `2` left over.
4. Line 4 computes `3 ^ 2`, which is `3 * 3`, so `9`.
5. Line 5 negates `squared` with unary `-`, giving `-9`.
6. Lines 6 to 9 print `2`, `2`, `9`, and `-9`.

## Join strings and measure length

The `..` operator glues two [strings](https://create.roblox.com/docs/luau/strings) into one. The `#` operator measures the length of a string in characters.

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local firstName = "Maya"
local hello = "Hi, " .. firstName
local nameLength = #firstName
print(hello)
print(nameLength)
```

```txt
Hi, Maya
4
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 stores `"Maya"` in `firstName`.
3. Line 3 joins `"Hi, "` and `"Maya"` with `..` into `"Hi, Maya"`.
4. Line 4 counts the characters in `"Maya"` with `#` and stores `4`.
5. Line 5 prints `Hi, Maya`.
6. Line 6 prints `4`.

Notice that `..` adds no space by itself. The space in the output comes from the space inside `"Hi, "`. When words run together unexpectedly, the missing space is almost always yours to add.

## Comparisons give booleans

Comparisons ask a question and answer with a boolean: `true` or `false`. Luau has six: `==` (equal), `~=` (not equal), `<`, `>`, `<=`, `>=`. Read `~=` as "not equal to". Learn [booleans](https://create.roblox.com/docs/luau/booleans) here because every `if` statement in [Conditionals and Loops](conditionals-and-loops.md) runs on them.

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local level = 5
local isReady = level >= 5
local isMaxed = level == 10
print(isReady)
print(isMaxed)
```

```txt
true
false
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 stores `5` in `level`.
3. Line 3 asks "is `5 >= 5`?" and stores the answer `true` in `isReady`.
4. Line 4 asks "is `5 == 10`?" and stores the answer `false` in `isMaxed`.
5. Lines 5 and 6 print `true` then `false`.

Use `==` with two equals signs to compare. One `=` assigns. Mixing them is a common beginner typo.

## Logic with and, or, not

Logical operators combine booleans into bigger questions. `and` is true only when both sides are true. `or` is true when at least one side is true. `not` flips a boolean around.

In Luau, `and` and `or` return one of their operands, not always `true` or `false`. `and` returns its first value when the first is falsy, otherwise its second value. `or` returns its first value when it is truthy, otherwise its second value. Programmers use `or` to pick defaults, as you will see below.

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local hasKey = true
local hasTicket = false
local canEnter = hasKey and hasTicket
local canTry = hasKey or hasTicket
local noKey = not hasKey
print(canEnter)
print(canTry)
print(noKey)
```

```txt
false
true
false
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 stores `true` in `hasKey`.
3. Line 3 stores `false` in `hasTicket`.
4. Line 4 computes `true and false`, which is `false`, and stores it in `canEnter`. Entry needs both.
5. Line 5 computes `true or false`, which is `true`, and stores it in `canTry`. Trying needs only one.
6. Line 6 flips `true` to `false` with `not` and stores it in `noKey`.
7. Lines 7 to 9 print `false`, `true`, `false`.

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local typedName = nil
local shownName = typedName or "Guest"
print(shownName)
```

```txt
Guest
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 stores [nil](https://create.roblox.com/docs/luau/nil) in `typedName`, meaning "no name typed yet".
3. Line 3 uses `or` to pick a fallback. Since `nil` is falsy, `or` returns `"Guest"`.
4. Line 4 prints `Guest`.

## Only nil and false are falsy

Every value in Luau acts as true or false inside a condition. Only two values are falsy: `nil` and `false`. Everything else is truthy. This surprises beginners twice: the number `0` is truthy, and the empty string `""` is truthy. Many other languages treat those as falsy, but Luau does not.

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local zeroCheck = not 0
local emptyCheck = not ""
local nilCheck = not nil
local falseCheck = not false
print(zeroCheck)
print(emptyCheck)
print(nilCheck)
print(falseCheck)
```

```txt
false
false
true
true
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 flips `0` with `not`. Since `0` is truthy, the result is `false`.
3. Line 3 flips `""` with `not`. An empty string is truthy, so the result is `false`.
4. Line 4 flips `nil` with `not`. `nil` is falsy, so the result is `true`.
5. Line 5 flips `false` with `not`, giving `true`.
6. Lines 6 to 9 print `false`, `false`, `true`, `true`.

When you check "did the player type anything", never test the string directly. An empty string passes. Compare against `""` instead. You will practice this in [Conditionals and Loops](conditionals-and-loops.md).

## Precedence and parentheses

Precedence decides which operator computes first. Luau computes in this order: `^`, then unary `not`, `-`, `#`, then `*` `/` `//` `%`, then `+` `-`, then `..`, then comparisons, then `and`, then `or`. Parentheses always win. When in doubt, add parentheses. They cost nothing and remove all doubt.

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local plain = 2 + 3 * 4
local grouped = (2 + 3) * 4
local powerFirst = 2 * 3 ^ 2
print(plain)
print(grouped)
print(powerFirst)
```

```txt
14
20
18
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 computes `3 * 4` first because `*` beats `+`, then adds `2`, giving `14`.
3. Line 3 computes `(2 + 3)` first because parentheses win, then `5 * 4` gives `20`.
4. Line 4 computes `3 ^ 2` first because `^` beats `*`, then `2 * 9` gives `18`.
5. Lines 5 to 7 print `14`, `20`, `18`.

## Convert with tonumber and tostring

Sometimes a number arrives as a string, like `"7"` from typed input. `tonumber` converts it into a real number so you can do math. `tostring` goes the other way and turns any value into its text form so you can join it with `..`. If `tonumber` cannot read a number in the string, it returns `nil`.

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local typed = "7"
local asNumber = tonumber(typed)
local doubled = asNumber + asNumber
local label = "Total: " .. tostring(doubled)
print(doubled)
print(label)
```

```txt
14
Total: 14
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 stores the string `"7"` in `typed`.
3. Line 3 converts `"7"` to the number `7` with `tonumber`.
4. Line 4 adds `7 + 7` and stores `14` in `doubled`. This works only because line 3 converted first.
5. Line 5 converts `14` back to `"14"` with `tostring` and joins it onto `"Total: "`.
6. Line 6 prints `14`.
7. Line 7 prints `Total: 14`.

## Common mistakes

**Using `=` instead of `==`.**

Run this to see it fail: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local level = 5
local isReady = level = 5
print(isReady)
```

```txt
Red syntax error on line 3: the script does not run until you compare with ==.
```

One `=` assigns, two `==` compare. Fix it with `==`. Run the fix the same way.

```luau
--!strict
local level = 5
local isReady = level == 5
print(isReady)
```

```txt
true
```

**Doing math on a string.**

Run this to see it fail: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local typed = "7"
local doubled = typed + typed
print(doubled)
```

```txt
ServerScriptService.Script:3: attempt to perform arithmetic (add) on string and number
```

The `+` operator needs numbers. Fix it by converting with `tonumber` first. Run the fix the same way.

```luau
--!strict
local typed = "7"
local asNumber = tonumber(typed)
local doubled = asNumber + asNumber
print(doubled)
```

```txt
14
```

**Treating `0` or `""` as falsy.**

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local coins = 0
local hasCoins = coins
if hasCoins then
	print("rich")
end
```

```txt
rich
```

This prints `rich` because `0` is truthy. Fix it with an explicit comparison. Run the fix the same way.

```luau
--!strict
local coins = 0
local hasCoins = coins > 0
if hasCoins then
	print("rich")
end
```

```txt
```

The fixed script prints nothing because `0 > 0` is false. An empty output is the correct result here.

**Reading `and` and `or` as always true or false.**

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local typedName = nil
local shownName = typedName or "Guest"
local isGuest = shownName == true
print(isGuest)
```

```txt
false
```

This prints `false` because `shownName` holds `"Guest"`, not `true`. Fix it by comparing against the actual fallback value. Run the fix the same way.

```luau
--!strict
local typedName = nil
local shownName = typedName or "Guest"
local isGuest = shownName == "Guest"
print(isGuest)
```

```txt
true
```

## Exercises

Run every solution below in a Script in ServerScriptService and press Play. Try each exercise yourself before you open its solution.

1. Store `17` and `5` in variables. Print their sum, difference, product, and quotient on four lines.

::: details Solution 1

```luau
--!strict
local first = 17
local second = 5
print(first + second)
print(first - second)
print(first * second)
print(first / second)
```

```txt
22
12
85
3.4
```

:::

2. Join `"Roblox"` and `"Studio"` with a space into one variable. Print the joined string and its length with `#`.

::: details Solution 2

```luau
--!strict
local joined = "Roblox" .. " " .. "Studio"
print(joined)
print(#joined)
```

```txt
Roblox Studio
13
```

:::

3. A ride needs height `48` or more. Store a height of `45`. Store a boolean that is true when the height passes. Print it.

::: details Solution 3

```luau
--!strict
local height = 45
local canRide = height >= 48
print(canRide)
```

```txt
false
```

:::

4. A player typed `"12"` as text. Convert it with `tonumber`, triple it, then build the string `"Score: "` plus the tripled value with `tostring` and `..`. Print the final string.

::: details Solution 4

```luau
--!strict
local typed = "12"
local asNumber = tonumber(typed)
local tripled = asNumber * 3
local label = "Score: " .. tostring(tripled)
print(label)
```

```txt
Score: 36
```

Line 3 converts the text to a number. Line 4 triples it. Line 5 converts back to text for joining.

:::

## Summary

You computed with arithmetic operators, joined strings with `..`, measured with `#`, compared values into booleans, combined conditions with `and`, `or`, and `not`, applied the truthiness rule that only `nil` and `false` are falsy, ordered math with precedence and parentheses, and converted with `tonumber` and `tostring`.

Next: [Conditionals and Loops](conditionals-and-loops.md).
