operators
α1✓ arithmetic-operators✓ comparison-operators✓ logical-operators✓ bitwise-operators◌ operator-overloading (α2)
operators
Precedence Table (Low to High)
| Precedence | Operator | Associativity | Description |
|---|---|---|---|
| 1 | || | left | logical or |
| 2 | && | left | logical and |
| 3 | == != | left | equality |
| 4 | < <= > >= | left | comparison |
| 5 | | | left | bitwise or |
| 6 | ^ | left | bitwise xor |
| 7 | & | left | bitwise and |
| 8 | << >> | left | shift |
| 9 | + - | left | additive |
| 10 | * / % | left | multiplicative |
| 11 | ! - ~ | right | prefix (unary) |
| 12 | () . [] | left | postfix |
Arithmetic Operators
x + y // addition
x - y // subtraction
x * y // multiplication
x / y // division
x % y // remainder
-x // negationRules:
- Operands must have the same numeric type
- No implicit widening or narrowing
- Explicit casts required:
u32(x),i64(y)
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:
- Operands must be integer types
- Shift amount requires explicit cast to operand width
Logical Operators
a && b // logical and (short-circuit)
a || b // logical or (short-circuit)
!a // logical notRules:
- Operands must be
Bool - No implicit boolean coercion
Comparison Operators
Equality
x == y // equality
x != y // inequalitySemantics:
- Scalars: value comparison
- Records: field-by-field comparison
- Unions: tag + payload comparison
- Views: pointer + length + region comparison
Ordering
x < y // less than
x <= y // less than or equal
x > y // greater than
x >= y // greater than or equalRules:
- Operands must have the same type
- Type must implement ordering (numeric types,
Char)
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 comparisonType 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 rangeExamples:
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
| Category | Operators | Operand Types |
|---|---|---|
| arithmetic | + - * / % | numeric |
| bitwise | & | ^ ~ << >> | integer |
| logical | && || ! | Bool |
| equality | == != | any (same type) |
| ordering | < <= > >= | ordered types |
| string | ++ | String |