Mojo operator reference
Precedence table
Operator precedence and associativity. Higher-precedence operators bind tighter. Unless noted, operators associate left to right.
From highest to lowest precedence
| Precedence | Operators | Notes |
|---|---|---|
| 1 | () [] . | Call, subscript, attribute |
| 2 | ** | Exponentiation, right-associative |
| 3 | +x -x ~x | Unary prefix |
| 4 | * @ / // % | Multiplicative |
| 5 | + - | Additive (addition, subtraction) |
| 6 | << >> | Bitwise shift (left, right) |
| 7 | & | Bitwise AND |
| 8 | ^ | Bitwise XOR (not transfers) |
| 9 | | | Bitwise OR |
| 10 | == != < <= > >= | Comparisons, chainable |
| 10 | in not in | Membership, chainable |
| 10 | is is not | Identity, chainable |
| 11 | not | Boolean NOT, prefix |
| 12 | and | Boolean AND, short-circuits |
| 13 | or | Boolean OR, short-circuits |
| 14 | if-else | Ternary, right-associative |
| 15 | := | Walrus operator |
Prefix operators: positive (+x), negative (-x), bitwise NOT
complement (~x)
Multiplicative operators: times (*), matrix multiplication (@),
divide (/, integer types round towards zero), truncating divide (//,
integer types round towards negative infinity), modulo (%).
Comparison operators: equality (==), inequality (!=), less-than (<),
less-than-or-equal (<=), greater-than (>), greater-than-or-equal (>=)
Right-associative operators
Most operators are left-associative. For example, a - b + c groups as
(a - b) + c. Two infix operators are right-associative: exponentiation
(a ** b) and Mojo's ternary if-else.
Exponentiation (**)
2 ** 3 ** 4groups as
2 ** (3 ** 4)Equivalent to pow(2, 81). In Mojo pow(a, b) and a ** b are
interchangeable.
Ternary (if-else)
"low" if value < 10 else "high" if value > 100 else "mid"groups as
"low" if value < 10 else ("high" if value > 100 else "mid")Chaining operations
All comparison operators can be chained:
a < b < c # equivalent to: (a < b) and (b < c)
a == b == c # equivalent to: (a == b) and (b == c)
a < b == c # equivalent to: (a < b) and (b == c)
a < b <= c != d # equivalent to: (a < b) and (b <= c) and (c != d)Each intermediate value is evaluated once.
-
Chaining only applies between operators at the same precedence.
2 ** 3 == 8isn't a chain. It evaluates as(2 ** 3) == 8since exponentiation binds tighter than comparison. -
Comparison, membership, and identity operators share the same precedence and chain together.
5 != a < b in cis valid and evaluates as(5 != a) and (a < b) and (b in c).
Implementing operators for custom types
Mojo doesn't limit operators use to built-in types. Each operator has a set of dunder methods your custom types can implement. Once added, you can use operators in code instead of calling methods.
Infix operator method types
Each infix operator has up to three forms that decide which operand's
method will run. For a op b:
- Forward: Mojo tries the forward method first.
a + bcallsa.__add__(b). - Reversed: If the forward method doesn't exist or can't handle
b's type, Mojo falls back to the reversed method onb.a + bcallsb.__radd__(a). - In-place: Called for compound assignment.
a += bcallsa.__iadd__(b).
For example, if a uses a CustomVector type:
a + 5: calls the forward methoda.__add__(5)5 + a: Int doesn't know custom types. Falls back to the reversed method,a.__radd__(5)a += 5: calls the in-placea.__iadd__(5)method
Arithmetic
Implement the methods directly on your struct to use instance OP instance, instance OP= instance.
| Operator | Forward | Reversed | In-place |
|---|---|---|---|
+ | __add__() | __radd__() | __iadd__() |
- | __sub__() | __rsub__() | __isub__() |
* | __mul__() | __rmul__() | __imul__() |
/ | __truediv__ | __rtruediv__() | __itruediv__() |
// | __floordiv__ | __rfloordiv__() | __ifloordiv__() |
% | __mod__() | __rmod__() | __imod__() |
** | __pow__() | __rpow__() | __ipow__() |
@ | __matmul__() | __rmatmul__() | __imatmul__() |
__pow__() and __ipow__() accept an optional third argument
(modulus).
In-place operators are syntactic sugar for the operator applied to the variable with assignment:
x += y # x = x + y
x -= y # x = x - y
x *= y # x = x * y
x /= y # x = x / y
x //= y # x = x // y
x %= y # x = x % y
x **= y # x = x ** y
x @= y # x = x @ yTraits:
Powable requires __pow__(), doesn't
provide a default.
Bitwise
Implement the methods directly on your struct to use a OP b, a OP= b.
| Operator | Forward | Reversed | In-place |
|---|---|---|---|
& | __and__() | __rand__() | __iand__() |
| | __or__() | __ror__() | __ior__() |
^ | __xor__() | __rxor__() | __ixor__() |
<< | __lshift__() | __rlshift__() | __ilshift__() |
>> | __rshift__() | __rrshift__() | __irshift__() |
Bitwise operators are typically implemented on integer and flag types. Like arithmetic operators, in-place bitwise operators are syntactic sugar for the operator applied to the variable with assignment:
x &= y # x = x & y
x |= y # x = x | y
x ^= y # x = x ^ y
x <<= y # x = x << y
x >>= y # x = x >> yUnary operators
Implement the methods directly on your struct to support
prefix operators like -x, +x, and ~x.
| Operator | Method |
|---|---|
-x | __neg__() |
+x | __pos__() |
~x | __invert__() |
Comparison operators
Implement the methods directly on your struct to use
a OP b.
| Operator | Method | Trait | Default? |
|---|---|---|---|
== | __eq__() | Equatable | Yes |
!= | __ne__() | Equatable | Yes |
< | __lt__() | Comparable | No |
<= | __le__() | Comparable | Yes |
> | __gt__() | Comparable | Yes |
>= | __ge__() | Comparable | Yes |
Traits:
Equatable provides
__eq__() if all your struct's fields conform to Equatable using
pairwise field comparison. __ne__() derives from __eq__().
Comparable provides
__le__(), __gt__(), and __ge__(), all derived from __lt__() and
__eq__(). You implement __lt__().
Comparable refines Equatable, so conforming to
Comparable requires both traits. If all your fields are
Equatable, you implement __lt__() at a minimum.
Identity and membership operators
Implement the methods directly on your struct to use a OP b.
| Operator | Method | Trait | Default? |
|---|---|---|---|
is | __is__() | Identifiable | No |
is not | __isnot__() | Identifiable | Yes |
in | __contains__() | — | No |
not in | __contains__() | — | No |
x in collection calls collection.__contains__(x). The method is on
the container, not the element. not in calls the same method and
negates the result.
is tests object identity, not equality. Stdlib types that implement
it include ArcPointer, PythonObject, and Optional (for is None
checks).
Traits:
Identifiable requires
__is__(). __isnot__() is provided (calls not (self is rhs)).
Subscript operators
Implement the methods directly on your struct to use a[key]
reads and a[key] = b assigns.
| Operation | Method |
|---|---|
obj[key] (read) | __getitem__() |
obj[key] = val (write) | __setitem__() |
Both accept variadic arguments (for multi-dimensional indexing).
Was this page helpful?
Thank you! We'll create more content like this.
Thank you for helping us improve!