ferrule documentation[styled mode]
specrfcshome

operators

Status: α1


operators


Precedence Table (Low to High)

PrecedenceOperatorAssociativityDescription
1||leftlogical or
2&&leftlogical and
3== !=leftequality
4< <= > >=leftcomparison
5|leftbitwise or
6^leftbitwise xor
7&leftbitwise and
8<< >>leftshift
9+ -leftadditive
10* / %leftmultiplicative
11! - ~rightprefix (unary)
12() . []leftpostfix

Arithmetic Operators

x + y    // addition
x - y    // subtraction
x * y    // multiplication
x / y    // division
x % y    // remainder
-x       // negation

Rules:


Bitwise Operators

x & y    // bitwise and
x | y    // bitwise or
x ^ y    // bitwise xor
~x       // bitwise not
x << n   // left shift
x >> n   // right shift (arithmetic for signed, logical for unsigned)

Rules:


Logical Operators

a && b   // logical and (short-circuit)
a || b   // logical or (short-circuit)
!a       // logical not

Rules:


Comparison Operators

Equality

x == y   // equality
x != y   // inequality

Semantics:

Ordering

x < y    // less than
x <= y   // less than or equal
x > y    // greater than
x >= y   // greater than or equal

Rules:


No Implicit Coercion

Ferrule does not perform implicit type coercion:

// WRONG
const x: i32 = 5;
const y: i64 = x;        // ERROR: type mismatch

// CORRECT
const y: i64 = i64(x);   // explicit cast
// WRONG
if count { ... }         // ERROR: expected Bool, found i32

// CORRECT
if count != 0 { ... }    // explicit comparison

Type Casting

Explicit casts use type constructor syntax:

const a: i32 = 100;
const b: i64 = i64(a);   // widening
const c: i16 = i16(a);   // narrowing (may truncate)
const d: f64 = f64(a);   // int to float
const e: i32 = i32(d);   // float to int (truncates)

String Concatenation

const greeting = "Hello, " ++ name ++ "!";

The ++ operator concatenates strings. Both operands must be String.


operator overloading (α2)

α1 does not support user-defined operator overloading. operators have fixed semantics for built-in types.

planned for α2: operators desugar to interface methods:

// a + b desugars to T.Add.add(a, b)
// a == b desugars to T.Eq.eq(a, b)
// a < b desugars to T.Ord.lt(a, b)

type Add<T> = { add: (T, T) -> T };

impl Add<Point> {
    add: function(a: Point, b: Point) -> Point {
        return Point { x: a.x + b.x, y: a.y + b.y };
    }
}

const p3 = p1 + p2;  // calls Point.Add.add(p1, p2)

see ../core/generics.md for more on the impl syntax.


Pattern Operators

These operators are valid only within pattern contexts:

a..b     // exclusive range pattern (a to b-1)
a..=b    // inclusive range pattern (a to b)
..       // rest pattern (matches remaining elements)
|        // or pattern (match either alternative)

The as keyword binds a value while matching (reuses the existing as keyword):

n as 0..=9 -> handle(n);  // bind n while matching range

Examples:

match value {
  0..=9    -> "digit";          // inclusive range
  10..100  -> "two digits";     // exclusive range
  n as _   -> handle(n);        // named binding
  A | B    -> handle_either();  // or pattern
}

match array {
  [first, .., last] -> ...;     // rest pattern
}

Summary

CategoryOperatorsOperand Types
arithmetic+ - * / %numeric
bitwise& | ^ ~ << >>integer
logical&& || !Bool
equality== !=any (same type)
ordering< <= > >=ordered types
string++String