Skip to content

Latest commit

 

History

History
201 lines (139 loc) · 5.68 KB

File metadata and controls

201 lines (139 loc) · 5.68 KB

Operators

Precedence

From lowest to highest:

Precedence Operators Description
1 |> Pipeline
2 || Logical or
3 && Logical and
4 == != < > <= >= Comparison
5 .. ..= Range
6 + - | ^ Add/subtract, bitwise or/xor
7 * / % << >> & &^ Multiply/divide, shifts, bitwise and/and-not
8 as Type cast
9 - ! ^ & Prefix (negation, not, bitwise not, reference)
10 . () [] ? .* Postfix (access, call, index, propagate, deref)

All binary operators are left-associative.

a + b * c          // a + (b * c)
a && b || c        // (a && b) || c
a + b |> f         // f(a + b)
0..1 + 2           // 0..(1 + 2)

Arithmetic

+, -, *, /, % require both operands to be the same numeric type. An untyped numeric literal adapts to the other operand.

Unary - negates a number. Disallowed for unsigned types:

  [error] Cannot negate unsigned type
   ╭─[example.lis:1:16]
 1 │ let x: uint8 = -1
   ·                ─┬
   ·                 ╰── cannot negate `uint8`
   ╰────
  help: Unsigned types cannot represent negative values

+ also concatenates strings:

let greeting = "hello" + ", " + "world"

Comparison

== and != compare any two values of the same type.

<, >, <=, >= compare numeric types and strings.

All comparison operators return bool.

Logical

&& and || short-circuit: the right operand is not evaluated if the left determines the result. ! negates. All require bool operands.

if is_valid && count > 0 {
  process()
}

Bitwise

&, |, ^, and &^ operate on integer values. Shifts (<<, >>) require an integer left operand and any integer right operand; the result has the left operand's type.

let mask = 0b1111
let value = 0b1010

let masked = value & mask
let toggled = value ^ mask
let shifted = value << 2
let inverted = ^value

Pipeline

The pipeline operator |> passes the left side as the first argument to the function on the right.

x |> f              // f(x)
x |> f(y)           // f(x, y)
x |> f(y, z)        // f(x, y, z)

Chains read top to bottom:

let result = items
  |> filter(is_valid)
  |> map(transform)
  |> sum()

// equivalent to: sum(map(filter(items, is_valid), transform))

The right side must be a function call. Lambdas are not allowed as pipeline targets.

Range

Range operators .. and ..= create range values.

Syntax Type Description
start..end Range<T> Exclusive upper bound
start..=end RangeInclusive<T> Inclusive upper bound
start.. RangeFrom<T> No upper bound
..end RangeTo<T> Exclusive, no lower bound
..=end RangeToInclusive<T> Inclusive, no lower bound

Ranges are used in for loops and slice indexing:

for i in 0..5 {
  fmt.Println(i)              // 0, 1, 2, 3, 4
}

for i in 0..=5 {
  fmt.Println(i)              // 0, 1, 2, 3, 4, 5
}

let slice = items[1..4]       // elements at indices 1, 2, 3

Slice sub-slicing is safe by default. The resulting sub-slice has its capacity capped to its length, so append on a sub-slice always allocates a new backing array and never silently mutates the original.

🧿 See safety.md

Reference and dereference

&expr creates a Ref<T>. ref.* dereferences it.

let x = 42
let r = &x
let value = r.*              // 42

📚 See 07-pointers.md

Indexed access

Slices and maps support bracket indexing:

let nums = [10, 20, 30]
let first = nums[0]          // 10

let mut ages = Map.new<string, int>()
ages["Alice"] = 20
let age = ages["Alice"]      // 20

Bracket access panics if the index is out of bounds (slices) or returns the zero value if the key is missing (maps). For safe access that returns Option<T>, use .get(). See safety.md

let safe = nums.get(0)       // Some(10)
let missing = nums.get(99)   // None

Compound assignment

+=, -=, *=, /=, %=, &=, |=, ^=, &^=, <<=, >>= combine an operation with an assignment. The target must be mutable:

let mut count = 0
count += 1

let mut total = 10.0
total *= 1.5

Mutation through a Ref<T> does not require mut on the binding.

📚 See 07-pointers.md

Error propagation

The ? operator propagates errors from Result and None from Option.

📚 See 09-error-handling.md

Type cast

The as operator converts between numeric types and between string and Slice<byte> or Slice<rune>.

📚 See 02-types.md


02-types.md 04-control-flow.md