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

OperatorDescriptionExample
+Addition3 + 47
-Subtraction / unary negation10 - 37
*Multiplication4 * 520
/Division (truncates toward zero for ints)10 / 33
%Modulo (sign follows dividend)10 % 31
**Power2 ** 101024
//Floor division (rounds toward negative infinity)-7 // 2-4

Comparison

OperatorDescription
==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)                 -- 0

Logical

OperatorDescription
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

OperatorDescriptionExample
&Bitwise AND0xFF & 0x0F15
`\`Bitwise OR`0x0F \0xF0255`
^Bitwise XOR0x0F ^ 0xFF240
~Bitwise NOT~0xFF-256
<<Left shift1 << 38
>>Right shift8 >> 22

String

OperatorDescription
++Concatenation

Null Coalesce

let val = null ?? 42             -- 42
let val2 = 10 ?? 99             -- 10

Returns 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  -- 20

x |> 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])     -- true

Type 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)             -- 42

Optional Chaining

let obj = #{"a": #{"b": 42}}
println(obj?.a?.b)               -- 42
println(obj?.x?.y)               -- null (no error)

let x = null
println(x?.foo)                  -- null

Compound 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                           -- 2

Also available: &=, |=, ^=, <<=, >>=, **=.

Operator Precedence (lowest to highest)

  1. = += -= *= /= %= etc. (assignment)
  2. |> (pipe)
  3. ?? .. ..= (null coalesce, range)
  4. || or (logical or)
  5. && and (logical and)
  6. == != (equality)
  7. < > <= >= is in not in (comparison, membership)
  8. | (bitwise or)
  9. ^ (bitwise xor)
  10. & (bitwise and)
  11. << >> (bit shift)
  12. + - ++ (add, subtract, string concat)
  13. * / % // (multiply, divide, modulo, floor div)
  14. ** (power, right-associative)
  15. as (cast)
  16. Unary: - ! not ~ (prefix)
  17. Postfix: ?. . [] () (access, call)