Beginner

Operators in Mojo

Explore arithmetic, comparison, logical, and bitwise operators in Mojo with practical Docker-ready examples

Operators are the building blocks of every expression you write. In Mojo, operators look and behave almost exactly like their Python counterparts—+, -, *, /, //, %, **, ==, and, or, and not all work as you would expect. The difference is what happens under the hood: when your variables have concrete types, Mojo’s MLIR-based compiler lowers these operators to native machine instructions, with no interpreter overhead.

Because Mojo is a Python superset with optional static typing, you can use operators in a relaxed Python style inside def functions, or in a strict, type-checked style inside fn functions. The compiler picks the right instructions based on the operand types: integer addition becomes a hardware add, floating-point division becomes an FPU instruction, and so on.

This tutorial walks through the operator categories you’ll use most: arithmetic, comparison, logical, bitwise, and compound assignment. Each example is a small, runnable Mojo program you can build and execute through the Docker image.

Arithmetic Operators

Mojo supports the same set of arithmetic operators as Python, including floor division (//), modulo (%), and exponentiation (**).

Create a file named arithmetic.mojo:

def main():
    var a: Int = 17
    var b: Int = 5

    print("a + b =", a + b)
    print("a - b =", a - b)
    print("a * b =", a * b)
    print("a / b =", Float64(a) / Float64(b))
    print("a // b =", a // b)
    print("a % b =", a % b)
    print("a ** b =", a ** b)
    print("-a =", -a)

True division (/) produces a floating-point result, so the integer operands are converted explicitly to Float64. Floor division (//) keeps the result as an integer, and ** raises the left operand to the power of the right.

Comparison and Logical Operators

Comparison operators (==, !=, <, <=, >, >=) return Bool values. Mojo’s logical operators—and, or, not—short-circuit just like in Python.

Create a file named comparison.mojo:

def main():
    var x: Int = 10
    var y: Int = 20

    print("x == y:", x == y)
    print("x != y:", x != y)
    print("x < y:", x < y)
    print("x <= 10:", x <= 10)
    print("x > y:", x > y)
    print("x >= 10:", x >= 10)

    var in_range: Bool = x > 0 and x < 100
    var is_edge: Bool = x == 0 or y == 20
    print("0 < x < 100:", in_range)
    print("x == 0 or y == 20:", is_edge)
    print("not in_range:", not in_range)

Mojo also supports Python-style chained comparisons. 0 < x < 100 is equivalent to 0 < x and x < 100 and evaluates x exactly once.

Bitwise Operators

Bitwise operators work on the binary representation of integers. They are useful for flag manipulation, low-level encoding, and—because Mojo compiles to native code—for squeezing maximum performance out of integer-heavy loops.

Create a file named bitwise.mojo:

def main():
    var a: Int = 12   # 0b1100
    var b: Int = 10   # 0b1010

    print("a & b =", a & b)    # AND  -> 0b1000 = 8
    print("a | b =", a | b)    # OR   -> 0b1110 = 14
    print("a ^ b =", a ^ b)    # XOR  -> 0b0110 = 6
    print("~a =", ~a)          # NOT  -> -13 (two's complement)
    print("a << 2 =", a << 2)  # left shift  -> 48
    print("a >> 1 =", a >> 1)  # right shift -> 6

~a produces -(a + 1) in two’s complement, which is why ~12 is -13. Shifts by n positions are equivalent to multiplying or dividing by 2**n, but they map to single hardware instructions.

Compound Assignment and Precedence

Compound assignment operators (+=, -=, *=, /=, //=, %=, **=, plus the bitwise variants) update a variable in place. They require the variable to be declared with var so that it is mutable.

Create a file named assignment.mojo:

def main():
    var total: Int = 0
    total += 10
    total += 5
    total -= 3
    total *= 2
    print("total =", total)

    # Operator precedence: ** binds tighter than * which binds tighter than +
    var result: Int = 2 + 3 * 4 ** 2
    print("2 + 3 * 4 ** 2 =", result)

    # Parentheses change the grouping
    var grouped: Int = (2 + 3) * 4 ** 2
    print("(2 + 3) * 4 ** 2 =", grouped)

    # Boolean short-circuit: the right side is never evaluated when unnecessary
    var safe: Bool = total != 0 and (100 // total) > 0
    print("safe check:", safe)

Mojo’s precedence rules follow Python’s: exponentiation binds tightest, followed by unary -, then *//////%, then +/-, then comparison, then not, and, or. When in doubt, parentheses make intent explicit and cost nothing at runtime.

Running with Docker

1
2
3
4
5
6
7
8
# Pull the official image
docker pull codearchaeology/mojo:latest

# Run each example
docker run --rm -v $(pwd):/app -w /app codearchaeology/mojo:latest mojo arithmetic.mojo
docker run --rm -v $(pwd):/app -w /app codearchaeology/mojo:latest mojo comparison.mojo
docker run --rm -v $(pwd):/app -w /app codearchaeology/mojo:latest mojo bitwise.mojo
docker run --rm -v $(pwd):/app -w /app codearchaeology/mojo:latest mojo assignment.mojo

Expected Output

Running arithmetic.mojo:

a + b = 22
a - b = 12
a * b = 85
a / b = 3.4
a // b = 3
a % b = 2
a ** b = 1419857
-a = -17

Running comparison.mojo:

x == y: False
x != y: True
x < y: True
x <= 10: True
x > y: False
x >= 10: True
0 < x < 100: True
x == 0 or y == 20: True
not in_range: False

Running bitwise.mojo:

a & b = 8
a | b = 14
a ^ b = 6
~a = -13
a << 2 = 48
a >> 1 = 6

Running assignment.mojo:

total = 24
2 + 3 * 4 ** 2 = 50
(2 + 3) * 4 ** 2 = 80
safe check: True

Key Concepts

  • Python-familiar syntax+, -, *, /, //, %, ** and the comparison/logical operators behave the same as in Python.
  • True vs floor division/ always yields a floating-point result; // performs floor division and preserves integer types.
  • Compile-time lowering — When operand types are known, Mojo’s compiler emits direct machine instructions, so operators carry no interpreter overhead.
  • Chained comparisons — Expressions like 0 < x < 100 work natively and evaluate the middle term only once.
  • Short-circuit logicand and or stop evaluating as soon as the result is determined, which is useful for guarding against division by zero or null-like values.
  • Bitwise operators on Int&, |, ^, ~, <<, and >> map to hardware instructions, making them ideal for flags, masks, and low-level encoding.
  • Mutability is explicit — Compound assignment requires var declarations; function arguments are immutable by default unless declared inout.
  • Standard precedence — Mojo follows Python’s precedence rules. When mixing arithmetic, comparison, and logical operators, parentheses make intent obvious at no runtime cost.

Running Today

All examples can be run using Docker:

docker pull codearchaeology/mojo:latest
Last updated:

Comments

Loading comments...

Leave a Comment

2000 characters remaining