Mastering Swift's Development Blog

Follow Us On Twitter
  • Jon Hoffman

Operator Methods and Custom Operators

Updated: Jul 16


Operator Methods

Operator methods enables us to add implementations of standard Swift operators to our custom types. This is a very useful feature because it enables us to provide common functionality to our custom types using known operators like the addition, and inverse operators. Let’s take a look at how to do this but first let’s create a custom type called Mypoint:


struct MyPoint {
    var x = 0
    var y = 0
}

The MyPoint structure defines a two-dimensional point on a graph using the standard X and Y coordinates. Now let’s add three operator methods to this type. The operators that we will add are the addition (+), addition assignment (+=) and the inverse operator (-). The addition operator and the addition assignment operator are infix operators because there is a left and right operand (values) to the operation while the inverse operator is a prefix operator because it is used before a single value. We also have postfix operators which is used at the end of a single value. Here is how we would add the operators using an extension:


extension MyPoint {
    static func + (left: MyPoint, right: MyPoint) -> MyPoint {
        return MyPoint(x: left.x + right.x, y: left.y + right.y)
    }
    static func += (left: inout MyPoint, right: MyPoint) {
        left.x += right.x
        left.y += right.y
    }
    static prefix func -(point: MyPoint) -> MyPoint {
        return MyPoint(x: -point.x, y: -point.y)
    }
}

When we add operator methods to our types, we add them as static functions using the operator symbols as the method names. When we add a prefix or postfix operators, we also include the prefix or postfix keyword before the function declaration as shown in our code.


The addition operator is an infix operator; therefore, it takes two input parameters of the MyPoint type. One parameter is for the MyPoint instances that is to the left side of the addition operator and the other parameter is for the MyPoint instance that is to the right of the addition operator.


The addition assignment operator is also an infix operator; therefore, it also takes two input parameters of the MyPoint type. The main difference from the addition operator is the resulting value of the addition operation is assigned to the MyPoint instance that is to the left side of the addition assignment operator therefore this parameter is designated as an inout parameter so the results can be returned within that instance.


The final operator method that we added is the inverse operator. This operator is a prefix operator where it is used before an instance of the MyPoint type therefore it only takes a single parameter of the MyPoint type. Let’s see how these operators’ work.


let firstPoint = MyPoint(x: 1, y: 4)
let secondPoint = MyPoint(x: 5, y: 10)
var combined = firstPoint + secondPoint
print("\(combined.x), \(combined.y)")

combined += firstPoint
print("\(combined.x), \(combined.y)")

let inverse = -combined
print("\(inverse.x), \(inverse.y)")

With this code we begin by defining two points and then adding them together using the addition operator that we created. The results of this operator are put in the new combined instance of the MyPoint type. The combined instance will contain the values of x as 6 and y as 14.


We then use the addition assignment operator that we created to add the values in the firstPoint instance to the values in the combined instance. The results of this operation is put in the combined instance of the MyPoint type. The combined instance now contains the values of x as 7 and y as 14.


Finally, we use the inverse operator on the combined instance of the MyPoint type to reverse the values and save the new values in the inverse instance of the MyPoint type. The inverse instance contains the values of x as -7 and y as -18.


We are not limited to using only current operators but we can also create our own custom operators as well. Let’s see how we can do this.


Custom Operators

Custom operators enable us to declare and implement our own operators outside of the standard operators provided by the Swift language. New operators must be declared globally using the operator keyword. They must also be defined with the infix, prefix or postfix keywords. Once an operator is defined globally, we are then able to add them to our types using the operator methods as shown in the last section. Let’s take a look at this by adding two new operators, the • which we will use to multiple two points together and the •• which will be used to square a value. We will add these operators to the MyPoint type that we created in the last section.


NOTE
The • symbol can be typed by holding down the option key and pressing the number 8 on a computer running MacOS

The first thing we need to do is to declare the operators globally. This can be done with the following code:


infix operator •
prefix operator ••

Notice that we define what type of operator it is (infix, prefix or postfix) followed by the operator keyword and then the symbol(s) that will be used for the operator. Now we can use them exactly like we do normal operators with our MyPoint type:


extension MyPoint {
    static func  (left: MyPoint, right: MyPoint) -> MyPoint {
        return MyPoint(x: left.x * right.x, y: left.y * right.y)
    }
    
    static prefix func •• (point: MyPoint) -> MyPoint {
        return MyPoint(x: point.x * point.x, y: point.y * point.y)
    }
}

These new custom operators are added to the MyPoint type exactly as we added standard operators, using static functions. We are now able to use these operators exactly like we would used standard operators


let multiplied = firstPoint • secondPoint
print("\(multiplied.x), \(multiplied.y)")

let squared = ••secondPoint
print("\(squared.x), \(squared.y)")

In the first line we use the • operator to multiple two instances of the MyPoint type together. The results are put in the multiplied instance of the MyPoint type. The multiplied instance will not contain the values of x as 5 and y as 40.


We then use the •• operator to square the value of the secondPoint instance and put the new value in the squared instance. The squared instance will now contain the values of x as 25 and y as 100.


This article was taken from Chapter 15, Advanced and Custom Operators, of my Mastering Swift 5.3 book. If you would like to read more, you can order the book from Amazon


masteringSwift.jpeg

Mastering Swift 5.3

The sixth edition of this bestselling book, updated to cover through version 5.3 of the Swift programming language

Amazon

Packt

pop.jpeg

Protocol Oriented Programming

Embrace the Protocol-Oriented design paradigm, for better code maintainability and increased performance, with Swift.

Amazon

Packt