+++ title = "6. Operators" weight = 6 +++
Zen C supports operator overloading for user-defined structs by implementing specific method names.
| Category | Operator | Method Name |
|---|---|---|
| Arithmetic | +, -, *, /, %, ** |
add, sub, mul, div, rem, pow |
| Comparison | ==, != |
eq, neq |
<, >, <=, >= |
lt, gt, le, ge |
|
| Bitwise | &, |, ^ |
bitand, bitor, bitxor |
<<, >> |
shl, shr |
|
| Unary | - |
neg |
! |
not |
|
~ |
bitnot |
|
| Index | a[i] |
get(a, i) |
a[i, j] |
get(a, i, j) |
|
a[i] = v |
set(a, i, v) |
Note on String Equality:
string == stringperforms value comparison (equivalent tostrcmp).char* == char*performs pointer comparison (checks memory addresses).- Mixed comparisons (e.g.
string == char*) default to pointer comparison.
Example:
impl Point {
fn add(self, other: Point) -> Point {
return Point{x: self.x + other.x, y: self.y + other.y};
}
}
let p3 = p1 + p2; // Calls p1.add(p2)
Multi-Index Example:
struct Matrix {
data: int[9];
}
impl Matrix {
fn get(self, row: int, col: int) -> int {
return self.data[row * 3 + col];
}
}
let m = Matrix{data: [1,0,0, 0,1,0, 0,0,1]};
let val = m[1, 2]; // Calls Matrix.get(m, 1, 2)
These operators are built-in language features and cannot be overloaded directly.
| Operator | Name | Description |
|---|---|---|
|> |
Pipeline | x |> f(y) desugars to f(x, y) |
?? |
Null Coalescing | val ?? default returns default if val is NULL (pointers) |
??= |
Null Assignment | val ??= init assigns if val is NULL |
?. |
Safe Navigation | ptr?.field accesses field only if ptr is not NULL |
? |
Try Operator | res? returns error if present (Result/Option types) |
|> Pipeline -- chain calls without nesting
fn double(x: int) -> int { return x * 2; }
fn add(a: int, b: int) -> int { return a + b; }
let res = 5 |> double |> add(10);
// Equivalent to: add(double(5), 10) → 20
?? Null Coalescing -- fallback for nullable pointers
let p: int* = NULL;
let default_val = &42;
let val = p ?? default_val;
assert(*val == 42);
??= Null Assignment -- assign only if NULL
let p: int* = NULL;
p ??= &42;
assert(*p == 42);
?. Safe Navigation -- access field without NULL check
struct Point { x: int; y: int; }
let p: Point* = NULL;
let x = p?.x; // returns 0/default instead of crashing
? Try Operator -- short-circuit on error
import "std/result.zc"
fn try_work() -> Result<int> {
let inner = may_fail();
let val = inner?; // returns Err early if inner is Err
return Result<int>::Ok(val * 2);
}
Auto-Dereference:
Pointer field access (ptr.field) and method calls (ptr.method()) automatically dereference the pointer, equivalent to (*ptr).field.