Operators

Learn all Topaz operators with a complete guide. Master the usage and precedence of arithmetic, comparison, logical, bitwise, assignment, and special operators.

Topaz provides various operators to manipulate and calculate data. Understanding the exact behavior and precedence of all operators is crucial. ⚡

🔢 Arithmetic Operators

Basic Arithmetic Operations

// Basic arithmetic operators
let a = 10
let b = 3

let addition = a + b        // 13
let subtraction = a - b     // 7  
let multiplication = a * b  // 30
let division = a / b        // 3.333...
let remainder = a % b       // 1
let exponentiation = a ** b // 1000

print("Addition: {addition}")
print("Subtraction: {subtraction}")
print("Multiplication: {multiplication}")
print("Division: {division}")
print("Remainder: {remainder}")
print("Exponentiation: {exponentiation}")

Unary Operators

let positive = +42     // 42 (explicit positive)
let negative = -42     // -42 (negation)

let number = 15
let negated = -number  // -15

print("Original value: {number}")
print("Negated: {negated}")

Increment/Decrement

Topaz v4 does not support ++/--. Use explicit reassignment with let mut.

let mut counter = 5
counter = counter + 1
counter = counter - 1

Compound Assignment Operators

let mut value = 10

value += 5     // value = value + 5 = 15
value -= 3     // value = value - 3 = 12  
value *= 2     // value = value * 2 = 24
value /= 4     // value = value / 4 = 6
value %= 4     // value = value % 4 = 2
value **= 3    // value = value ** 3 = 8

print("Final value: {value}")

🔍 Comparison Operators

Basic Comparisons

let x = 10
let y = 20
let z = 10

// Equality comparison
let equal = x == z         // true
let notEqual = x != y      // true

// Size comparison
let lessThan = x < y            // true
let lessThanOrEqual = x <= z    // true
let greaterThan = y > x         // true
let greaterThanOrEqual = z >= x // true

print("x == z: {equal}")
print("x != y: {notEqual}")
print("x < y: {lessThan}")
print("y > x: {greaterThan}")

Type-Safe Comparison

// Topaz enforces type-safe comparison
let integer = 42
let float = 42.0
let string = "42"

// Only same types can be compared
let intComparison = integer == 42        // true
let floatComparison = float == 42.0      // true

// Different type comparison requires explicit conversion
let stringComparison = integer.toString() == string  // true
let numberComparison = integer == parseInt(string)   // true

print("Type conversion comparison: {stringComparison}")

Special Comparison Operators

Topaz v4 does not include a spaceship (<=>) operator.

🧠 Logical Operators

Basic Logical Operations

let trueValue = true
let falseValue = false

// Logical AND
let andResult = trueValue && falseValue     // false
let andResult2 = trueValue && trueValue     // true

// Logical OR  
let orResult = trueValue || falseValue      // true
let orResult2 = falseValue || falseValue    // false

// Logical NOT
let notResult = !trueValue           // false
let notResult2 = !falseValue         // true

print("AND result: {andResult}")
print("OR result: {orResult}")
print("NOT result: {notResult}")

Short-circuit Evaluation

function sideEffectFunction() -> bool {
    print("Function was called!")
    return true
}

// AND short-circuit - second not executed if first is false
let shortAnd = false && sideEffectFunction()  // Function not called

// OR short-circuit - second not executed if first is true
let shortOr = true || sideEffectFunction()   // Function not called

print("Short AND: {shortAnd}")
print("Short OR: {shortOr}")

Null Coalescing Operator

// Null coalescing operator (??)
let value1: Option<string> = None
let value2: Option<string> = Some("default")
let value3 = "fallback"

let result1 = value1 ?? "none"           // "none"
let result2 = value2 ?? "none"           // "default"  
let result3 = value1 ?? value2 ?? value3 // "default"

print("Null coalescing result: {result1}")

// With Option values
let user = { name: "TopazDev", age: Some(25) }
let age = match user.age { case Some(v) => v; case None => 0 }
print("Age: {age}")

Null‑Coalescing Assignment (??=)

Statement‑only assignment that initializes a variable if it is currently None/null. It does not produce an expression value and is right‑associative.

let mut name: Option<string> = None
name ??= Some("guest")     // name becomes Some("guest")
name ??= Some("override")  // no-op (already Some)

// Right-associative
a ??= b ??= Some(1)   // same as: a ??= (b ??= Some(1))

🔧 Bitwise / Shift Operators

Not part of Topaz v4. Note that >> is reserved for function composition (see below), not bit shifting.

🎯 Special Operators

Type Operators

typeof/instanceof are not Topaz v4 operators. Use pattern matching or library introspection utilities.

Range Operators

// Range operators (.. inclusive, ..< exclusive upper bound)
let inclusive = 1..5       // 1, 2, 3, 4, 5
let exclusive = 1..<5      // 1, 2, 3, 4

for i in inclusive { print(i) }
for i in exclusive { print(i) }

Membership Operator (in)

// Arrays/Lists/Sets
let ok1 = 3 in [1, 2, 3]                  // true
let ok2 = "a" in Set.of("a", "b")        // true

// Map keys (via keys view)
let hasId = "id" in userMap.keys          // bool

// Ranges
let inside = 5 in 1..10                    // true
let outside = 10 in 1..<10                 // false

Spread Operator

Not part of Topaz v4 syntax.

Optional Chaining (?.)

Option-safe only. Parses when the left-hand side is Option<T> or a nullable union (e.g., T | null). This is not generic object chaining; use . for regular members.

let user: Option<{ name: string, profile: Option<{ city: string }> }> =
    Some({ name: "Ann", profile: Some({ city: "Seoul" }) })

let nameOpt = user?.name              // Option<string>
let cityOpt = user?.profile?.city     // Option<string>
let city    = user?.profile?.city ?? "Unknown"  // string

let noneUser: Option<{ name: string }> = None
let fallback = noneUser?.name ?? "guest"       // "guest"

// Desugars to Option.map/flatMap chains
// user?.profile?.city  ≃  user |> Option.flatMap(_, u => u.profile) |> Option.map(_, p => p.city)

Pipe Operator

// Pipe operator (|>)
let result = 10
    |> (x => x * 2)        // 20
    |> (x => x + 5)        // 25
    |> (x => x.toString())  // "25"

// Useful for function chaining
let data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    |> (arr => arr.filter(x => x % 2 == 0))  // [2, 4, 6, 8, 10]
    |> (arr => arr.map(x => x * x))           // [4, 16, 36, 64, 100]
    |> (arr => arr.reduce((a, b) => a + b))  // 220

print("Pipe result: {result}")
print("Chaining result: {data}")

⚡ Operator Precedence (Topaz v4)

v4
// High → Low; associativity in parentheses
1) Calls/Index/Member: () [] . ?. (left)
2) Exponentiation: ** (right)
3) Unary: + - ! (right)
4) Multiplicative: * / % (left)
5) Additive: + - (left)
6) Range: .. ..< (left)  // lower than arithmetic, higher than comparison
7) Comparison: < <= > >= == != in (left)
8) Logical AND: && (left)
9) Logical OR: || (left)
10) Null coalescing: ?? (left)
11) Function composition: >> (right)
12) Pipeline: |> (left)
13) Assignment: = …, ??= (right)

// Composition vs Pipeline precedence
// |> has lower precedence than >>
let h = f >> g
let x = input |> h          // equals: input |> (f >> g)

// Range precedence
let within = 3 >= (1..5).min() && 3 <= (1..5).max()

Function Composition (>>)

// Point-free style
let normalize = trim >> toLowerCase >> collapseSpaces
print(normalize("  Hello   WORLD  "))  // "hello world"

🔄 Operator Overloading

Custom Type Operators

// Implementing operators for structs
struct Vector {
    x: float,
    y: float
}

impl Vector {
    // Overload + operator
    function +(other: Vector) -> Vector {
        return Vector { x: self.x + other.x, y: self.y + other.y }
    }
    
    // Overload * operator (scalar multiplication)
    function *(scalar: float) -> Vector {
        return Vector { x: self.x * scalar, y: self.y * scalar }
    }
    
    // Overload == operator
    function ==(other: Vector) -> bool {
        return self.x == other.x && self.y == other.y
    }
    
    // String conversion
    function toString() -> string {
        return "Vector({self.x}, {self.y})"
    }
}

// Usage examples
let vector1 = Vector { x: 3.0, y: 4.0 }
let vector2 = Vector { x: 1.0, y: 2.0 }

let sum = vector1 + vector2             // Vector(4.0, 6.0)
let scaled = vector1 * 2.0             // Vector(6.0, 8.0)
let equal = vector1 == vector2         // false

print("Vector sum: {sum}")
print("Vector scaled: {scaled}")
print("Vectors equal: {equal}")

🛡️ Safe Operator Usage

1. Overflow Handling

// Checked arithmetic operations
let largeNum1 = 2147483647  // max int value
let largeNum2 = 1

// Safe addition (overflow check)
match largeNum1.checkedAdd(largeNum2) {
    case Some(result) => print("Safe addition: {result}")
    case None => print("Overflow occurred!")
}

// Saturating operations (clamp to max/min values)
let saturatingAdd = largeNum1.saturatingAdd(largeNum2)  // stays at max int
print("Saturating addition: {saturatingAdd}")

2. Division by Zero Prevention

function safeDivide(numerator: float, denominator: float) -> Result<float, string> {
    if denominator == 0.0 {
        return Err("Cannot divide by zero")
    }
    return Ok(numerator / denominator)
}

// Usage example
match safeDivide(10.0, 0.0) {
    case Ok(result) => print("Division result: {result}")
    case Err(error) => print("Error: {error}")
}

3. Type Safety

// Ensure safety with explicit type conversion
let stringNumber = "123"
let actualNumber = match parseInt(stringNumber) {
    case Ok(number) => number
    case Err(_) => {
        print("Number conversion failed")
        0  // default value
    }
}

let result = actualNumber + 100
print("Safe calculation result: {result}")

📊 Performance Optimization Tips

1. Expensive Operation Optimization

// Use multiplication instead of exponentiation (for small exponents)
let square = value * value           // instead of value ** 2
let cube = value * value * value     // instead of value ** 3

// Use multiplication instead of division
let half = value * 0.5          // instead of value / 2

// Optimize modulo operations (powers of 2)
let remainder = value & 7          // instead of value % 8 (8 = 2^3)

2. Leverage Short-circuit Evaluation

// Put expensive function calls later
let result = simpleCondition() && expensiveFunction()

// Optimize null checks with Option helpers
let value = object?.property?.subProperty ?? defaultValue

Understanding and properly using Topaz operators allows you to write efficient and safe code! Always keep operator precedence and type safety in mind. 🎯