Different from Objective-C, overriding or creating operator is supported in Swift. The simplest use case should be redefining some calculation. For example, there is a Vector2D
struct representing the 2D vector data structure.
struct Vector2D {
var x = 0.0
var y = 0.0
}
The code for adding two Vector2D
would be:
let v1 = Vector2D(x: 2.0, y: 3.0)
let v2 = Vector2D(x: 1.0, y: 4.0)
let v3 = Vector2D(x: v1.x + v2.x, y: v1.y + v2.y)
// v3 is {x 3.0, y 7.0}
There is no problem if we only want to do this once. But unfortunately, the adding operation is still a common one and we want to use it here and there. We would prefer to define an adding method for Vector2D
struct to make code neat.
By overriding the plus operator, we can simplify the adding operation:
func +(left: Vector2D, right: Vector2D) -> Vector2D {
return Vector2D(x: left.x + right.x, y: left.y + right.y)
}
The v3
assignment and all plus operation could be replaced with a +
operator from now on:
let v4 = v1 + v2
// v4 is {x 3.0, y 7.0}
Similarly, we could define -
(binary operator, means subtraction) or -
(unary operation, means negation) or some other operators. I believe that it would be better to leave it for your exercise.
Regardless the +
or -
, they are operators already existing in Swift. There is one more step if we need to define a NEW operator not existing in Swift yet. For example, we want to introduce a common used dot product operator into Vector2D
, which means getting the sum of the products of the corresponding entries in the two sequences of numbers. Follow the definition of dot product, and refer to the syntax of an operator, if we decide +*
as our operator, the code would be something like this:
func +* (left: Vector2D, right: Vector2D) -> Double {
return left.x * right.x + left.y * right.y
}
But the compiler will throw an error:
Operator implementation without matching operator declaration
Operators like +
, -
or *
are already defined in Swift's built-in library, while +*
is not. Before implementing it, we just have to declare it first. It will tell the compiler this sign is an operator:
infix operator +* {
associativity none
precedence 160
}
infix
It means that it is a binary operator. Both left-hand and right-hand are operand for it. If you want to write a unary operation, use
prefix
orpostfix
instead.
associativity
It defines the associative property of this operation. That means the order should be used when doing multiple operations of the same type. For example, addition and subtraction follow
left
, if there are multiple+
and-
, it should be calculated from the left one to right (except there is parentheses). Here, the result of dot product is aDouble
and it will never be used in another dot product operation. So we usenone
.
precedence
The priority of this operator. Higher priority number will make this operation happen earlier. In Swift, multiplication and division share a precedence of 150, and addition and subtraction are 140. We define 160 for dot product here, making it happen earlier than other four arithmetic operations.
By declaring it, the dot product for vector becomes much simpler:
let result = v1 +* v2
// Output is 14.0
Last but not least, you cannot define a Swift operator in the local scope, it must exist in global scope. That makes sense since you hardly just need a local operator or it is useless for users of your code. We should always remember, once we define an operator in global scope, it might conflict with the customized operators from other frameworks. Different from class name or method name, the conflict of operators cannot be solved by adding the framework name as a prefix - it is not valid syntax when using with an operator.
You would be better to make sure your operator is just a shortcut for a method, instead of implementing some unique logic in it. By doing so, if the operator conflicts with other framework, your users have a chance to use the method name at least. We should really avoid abusing customized operator, especially in a framework for others to use. The operator should be clear and precise, so it will cause no ambiguity or trouble.