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 fornil
.?.
: 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]]