Skip to content

Advanced Operators

Swift supports custom operators, overloading, and advanced bitwise operations, enabling expressive and flexible for domain-specific logic.

Operator Types

  • Infix: Between operands (e.g., a + b).
  • Precedence: Before operand (e.g., -a).
  • Postfix: After operand (e.g., a!).

Built-in Advanced Operators

Bitwise Operators

Operate on integer bits.

  • &: AND
  • |: OR
  • ^: XOR
  • ~: NOT
  • <<, >>: Shift left, right

Example:

swift
let flags = 0b1100 & 0b1010 // 0b1000 (8)
let shifted = 0b0001 << 2 // 0b0100 (4)
let inverted = ~0b1010 // 0b1111...10101
print(flags, shifted)

Nil-Coalescing and Optional Chaining

  • ??: Provides default for nil.
  • ?.: Safely accesses optional members.

Example:

swift
let optional: String? = nil
print(optional?.count ?? 0) // 0

Custom Operators

Defining Operators

Use operator to declare new operators.

Example: Power Operator:

swift
infix operator **: MultiplicationPrecedence
func ** (left: Double, right: Int) -> Double {
    return pow(left, Double(right))
}

print(2 * 3) // 8.0)

Precedence Groups

Define precedence and associativity.

Example:

swift
precedencegroup Exponentiation {
    higherThan: MultiplicationPrecedence
    associativity: left
}

infix operator ^^: Exponentiation
func ^^ (left: Double, right: Double) -> Double {
    return pow(left, right)
}

print(2 ^^ 3 * 2) // 16.0 (2^3 * 2)

Operator Overloading

Redefine operators for custom types.

Example: Vector Addition:

swift
struct Vector {
    let x, y: Double
    static func + (left: Vector, right: Vector) -> Vector {
        return Vector(x: left.x + right.x, y: left.y + right.y, right.y)
    }
    
    static func * (left: Double, right: Vector) -> Vector {
        return Vector(x: left * right.x, y: left * right.y)
    }
}

let v1 = Vector(x: 1, y: 2)
let v2 = Vector(x: 3, y: 4)
print(v1 + v2) // (4.0, 6.0)
print(2 * v1) // (2.0, 4.0)

Custom Operator Protocols

Implement protocols like Equatable, Comparable.

Example:

swift
extension Vector: Equatable {
    static func == (left: Vector, right: Vector) -> Bool {
        return left.x == right.x && left.y == right.y
    }
}

print(v1 == v2) // false

Operator Methods

Define operators as methods for clarity.

Example:

swift
extension Vector {
    func scaled(by factor: Double) -> Vector {
        return factor * self
    }
}

print(v1.scaled(by: 2)) // (2.0, 4.0)

Best Practices

  • Sparingly Use Custom Operators: Ensure clarity for readers.
  • Define Precedence: Avoid ambiguity in expressions.
  • Overload Intuitively: Match expected behavior (e.g., + for addition).
  • Document Operators: Explain custom operator semantics.
  • Test Thoroughly: Verify edge cases and associativity.
  • Avoid Overuse: Prefer methods for complex logic.

Troubleshooting

  • Ambiguous Operators: Use parentheses or explicit precedence.
  • Precedence Errors: Define clear precedence groups.
  • Overload Conflicts: Ensure unique signatures.
  • Performance: Profile custom operator usage.
  • Readability Issues: Refactor complex operators into methods.

Example: Comprehensive Operator Usage

swift
precedencegroup MatrixPrecedence {
    higherThan: AdditionPrecedence
    associativity: left
}

infix operator ***: MatrixPrecedence

struct Matrix {
    let rows: [[Double]]
    
    static func *** (left: Matrix, right: Matrix) -> Matrix {
        // Simplified matrix multiplication
        let result = [[left.rows[0][0] * right.rows[0][0]]]
        return Matrix(rows: result)
    }
    
    static func + (left: Matrix, right: Matrix) -> Matrix {
        let result = left.rows.enumerated().map { (i, row) in
            row.enumerated().map { (j, value) in
                value + right.rows[i][j]
            }
        }
        return Matrix(rows: result)
    }
}

extension Matrix: CustomStringConvertible {
    var description: String {
        return rows.map { $0.description }.joined(separator: "\n")
    }
}

let m1 = Matrix(rows: [[1, 2], [3, 4]])
let m2 = Matrix(rows: [[5, 6], [7, 8]])
print(m1 + m2)
// [[6.0, 8.0]
//  [10.0, 12.0]]

let m3 = Matrix(rows: [[2]])
let m4 = Matrix(rows: [[3]])
print(m3 *** m4) // [[6.0]]

Released under the MIT License.