Operators
Arithmetic, comparison, logical, bitwise, pipe, membership, type, and compound assignment operators with a full precedence table.
Summary
Assignment has the lowest precedence; postfix access and call have the highest. The pipe operator |> rebinds x |> f as f(x) and chains left-to-right. Null coalescing (??) returns the left operand if it is not null. Optional chaining (?.) short-circuits to null instead of throwing on a missing field. The spaceship operator (<=>) returns -1, 0, or 1. Logical and/or short-circuit and return the last evaluated operand, not a boolean.
Canonical
Arithmetic
| Operator | Description | Example |
|---|---|---|
+ | Addition | 3 + 4 → 7 |
- | Subtraction / unary negation | 10 - 3 → 7 |
* | Multiplication | 4 * 5 → 20 |
/ | Division (truncates toward zero for ints) | 10 / 3 → 3 |
% | Modulo (sign follows dividend) | 10 % 3 → 1 |
** | Power | 2 ** 10 → 1024 |
// | Floor division (rounds toward negative infinity) | -7 // 2 → -4 |
Comparison
| Operator | Description |
|---|---|
== | Equal |
!= | Not equal |
< | Less than |
> | Greater than |
<= | Less or equal |
>= | Greater or equal |
<=> | Spaceship (three-way: returns -1, 0, or 1) |
println(5 <=> 3) -- 1
println(3 <=> 5) -- -1
println(5 <=> 5) -- 0Logical
| Operator | Description | ||
|---|---|---|---|
and / && | Logical AND (short-circuit) | ||
or / `\ | \ | ` | Logical OR (short-circuit) |
not / ! | Logical NOT |
Short-circuit: and stops if the left side is falsy; or stops if the left side is truthy. The result is the last evaluated operand, not necessarily true/false.
Bitwise
| Operator | Description | Example | ||
|---|---|---|---|---|
& | Bitwise AND | 0xFF & 0x0F → 15 | ||
| `\ | ` | Bitwise OR | `0x0F \ | 0xF0 → 255` |
^ | Bitwise XOR | 0x0F ^ 0xFF → 240 | ||
~ | Bitwise NOT | ~0xFF → -256 | ||
<< | Left shift | 1 << 3 → 8 | ||
>> | Right shift | 8 >> 2 → 2 |
String
| Operator | Description |
|---|---|
++ | Concatenation |
Null Coalesce
let val = null ?? 42 -- 42
let val2 = 10 ?? 99 -- 10Returns the left side if it's not null, otherwise the right side.
Pipe
fn double(x) { x * 2 }
let r = 5 |> double -- 10
let n = [1, 2, 3] |> len -- 3
-- chain multiple
let result = 5 |> double |> double -- 20x |> f passes x as the first argument to f.
Membership
println(2 in [1, 2, 3]) -- true
println("a" in #{"a": 1}) -- true (checks keys)
println("ell" in "hello") -- true (substring check)
println(3 in 1..5) -- true
println(5 not in [1, 2, 3]) -- trueType Operators
-- is: runtime type check
println(42 is int) -- true
println("hi" is str) -- true
println(3.14 is float) -- true
println(42 is float) -- false
-- as: type cast
println(42 as float) -- 42.0
println(42 as str) -- "42"
println("42" as int) -- 42Optional Chaining
let obj = #{"a": #{"b": 42}}
println(obj?.a?.b) -- 42
println(obj?.x?.y) -- null (no error)
let x = null
println(x?.foo) -- nullCompound Assignment
All of these require a var binding on the left side.
var x = 10
x += 5 -- 15
x -= 3 -- 12
x *= 2 -- 24
x /= 4 -- 6
x %= 4 -- 2Also available: &=, |=, ^=, <<=, >>=, **=.
Operator Precedence (lowest to highest)
=+=-=*=/=%=etc. (assignment)|>(pipe)??....=(null coalesce, range)||or(logical or)&&and(logical and)==!=(equality)<><=>=isinnot in(comparison, membership)|(bitwise or)^(bitwise xor)&(bitwise and)<<>>(bit shift)+-++(add, subtract, string concat)*/%//(multiply, divide, modulo, floor div)**(power, right-associative)as(cast)- Unary:
-!not~(prefix) - Postfix:
?..[]()(access, call)