Written by Steve Johnson
Feb 07, 2017

Overloading Swift Operators

How to overload existing operators in Swift 3.x

Overloaded

Sometimes the obviously useful isn’t readily available.

On a recent client project, the code I was writing required me to manipulate many coordinates using CGSize and CGPoint and after a few calculations things were getting bulky.

One of the many features of Apple’s flagship language is the ability to ‘overload’ (basically, rewrite) existing operators (+, -, *, /, etc.). This allows you to redefine their functionality or add compatible operand types (operands being the values you wish to perform the operation on).

In this instance, I was adding multiplication functions to CGSize, CGPoint and CGFloat types and as a result was able to simplify the code nicely throughout the project, for example:

let largeSize = CGSize(width: smallSize.width * factor, height: smallSize.height * factor)

Became this:

let largeSize = smallSize * factor

That may not look like much of a saving, but once you start scaling up (excuse the pun), the improvements in simplicity and readability of your code are noticeable.

Overriding an operator is simple, you just declare your method in the root namespace and it becomes available app-wide.

Let’s look at the following code which provides the operator functionality shown above:

// lhs * rhs = output
func *(lhs: CGSize, rhs: CGFloat) -> CGSize {
    return CGSize(width: lhs.width * rhs, height: lhs.height * rhs)
}

With this function defined in the root namespace, every time you use the statement X * Y (where X is of type CGSize and Y is of type CGFloat) a CGSize struct will be returned containing the width and height of X, each multiplied by Y.

This operator is classed as binary because it ‘operates’ on two operands (values). Overloading operators is a very simple process, though I would caution you not to get too carried away, as ambiguity can be easily introduced.

For example:

// lhs - rhs = output
func -(lhs: String, rhs: String) -> String {
	return “\(Int(lhs) - Int(rhs))”
}

In this case: “12” - “2” = “10” While valid, this isn’t an obvious use of a String operator and a coder may have expected “Hello World” - “World” to remove one string from the other, resulting in “Hello “ whereas in this case, they would see “0” returned.

Custom Operators

If a standard set of operators is too limited for you,  Swift allows you to define your own.

Say you want to simplify the process for getting the square root of a number, you could define the square root character √ as an operator, for example:

let result = √144

( pressing ⌥ + v will give you the √ character)

To create a new operator you would  first declare it:

prefix operator √

The keyword here is operator, which must be prefixed with either prefix, infix or postfix depending on whether the operand is unary and placed before (prefix) or after (postfix) a single operand, or binary and placed between (infix) two operands.

As before, you define a function that matches the operator declaration:

prefix func √ (number: Double) {
	return sqrt(number)
}

This operator is classed as unary because it ‘operates’ on one operand (value).

Operators are so customisable that you can even set the precedence and ordering (remember BODMAS* in school?), but that’s a long story for another post; my purpose here was to provide a brief introduction to the subject.

Hopefully, your interest is sufficiently piqued for you to continue your own exploration of Swift and how it can be tailored to suit your coding needs.

Summary

  • Swift is a highly customisable language and with a bit of care, you can greatly improve the readability of your code.
  • Be mindful of ambiguities when overloading or customising operators and document your code to avoid this.
  • There is a lot of information on the net; always check which version of Swift it applies to.

*BODMAS: Brackets, Orders, Division or Multiplication, Addition or Subtraction. An easy mnemonic on the ordering of mathematical calculations, often taught in schools.

Top