In this Swift tutorial, you’ll learn how to create custom operators, overload existing operators and set operator precedence. By Owen L Brown.

Leave a rating/review
Save for later
Share

## Contents

20 mins

### Mixed Parameters? No Problem!

You can also multiply vectors by a number through scalar multiplication. To multiply a vector by two, you multiply each component by two. You’re going to implement this next.

One thing you need to consider is the order of the arguments. When you implemented addition, order didn’t matter because both parameters were vectors.

For scalar multiplication, you need to account for `Int * Vector` and `Vector * Int`. If you only implement one of these cases, the Swift compiler will not automatically know that you want it to work in the other order.

To implement scalar multiplication, add the following two functions below the subtraction function you’ve just added:

```static func * (left: Int, right: Vector) -> Vector {
return [
right.x * left,
right.y * left,
right.z * left
]
}

static func * (left: Vector, right: Int) -> Vector {
return right * left
}
```

To avoid writing the same code multiple times, your second function simply relays its arguments to the first one.

In mathematics, vectors have another interesting operation known as the cross-product. How cross-products work is beyond the scope of this tutorial, but you can learn more about them on the Cross product Wikipedia page.

Since using custom symbols is discouraged in most cases (who wants to open the Emoji menu while coding?), it would be very convenient to reuse the asterisk for cross-product operations.

Cross-products, unlike scalar multiplication, take two vectors as arguments and return a new vector.

```static func * (left: Vector, right: Vector) -> Vector {
return [
left.y * right.z - left.z * right.y,
left.z * right.x - left.x * right.z,
left.x * right.y - left.y * right.x
]
}
```

Now, add the following calculation to the bottom of your playground, leveraging both your multiplication and cross-product operators:

```vectorA * 2 * vectorB // (-14, -10, 22)
```

This code finds the scalar multiple of `vectorA` and 2, then finds the cross-product of that vector with `vectorB`. Note that the asterisk operator always goes from left to right, so the previous code is the same as if you had used parentheses to group the operations, like `(vectorA * 2) * vectorB`.

### Protocol Operators

Some operators are required members of protocols. For example, a type that conforms to `Equatable` must implement the `==` operator. Similarly, a type that conforms to `Comparable` must implement at least `<` and `==`, because `Comparable` inherits from `Equatable`. `Comparable` types may also optionally implement `>`, `>=`, and `<=`, but these operators have default implementations.

For `Vector`, `Comparable` doesn't really make a lot of sense, but `Equatable` does, since two vectors are equal if their components are all equal. You’ll implement `Equatable` next.

To conform to the protocol, add the following code at the end of your playground:

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

Add the following line to the bottom of your playground to test this out:

```vectorA == vectorB // false
```

This line returns `false` as expected, because `vectorA` has different components than `vectorB`.

Conforming to `Equatable` gives you more than the ability to check for equality of these types. You also gain access to `contains(_:)` for an `Array` of `Vector`s for free!

## Creating Custom Operators

Remember how I said that using custom symbols is usually discouraged? As always, there are exceptions to the rule.

A good rule of thumb about custom symbols is that you should only use them if the following are true:

• Their meanings are well-known or would make sense to someone reading the code.
• They are easy to type on the keyboard.

This last operator you will implement matches both of these conditions. The vector dot-product takes two vectors and returns a single scalar number. Your operator will multiply each value in a vector by its counterpart in the other vector, then add up all these products.

The symbol for dot-product is `•`, which you can easily type using Option-8 on your keyboard.

You might be thinking, "I can just do the same thing I did with every other operator in this tutorial, right?"

Unfortunately, you can't do that just yet. In the other cases, you are overloading an operator that already exists. For new custom operators, you need to create the operator first.

Directly underneath the `Vector` implementation, but above the `CustomStringConvertible` conformance extension, add the following declaration:

```infix operator •: AdditionPrecedence
```

This defines `•` as an operator that must be placed between two other values and has the same precedence as the addition operator `+`. Ignore precedence just for the moment because you'll come back to it.

Now that this operator has been registered, add its implementation at the end of your operators extension, immediately below the implementation of the multiplication and cross-product operators `*`:

```static func • (left: Vector, right: Vector) -> Int {
return left.x * right.x + left.y * right.y + left.z * right.z
}
```

Add the following code to the bottom of your playground to test this out:

```vectorA • vectorB // 15
```

Everything looks good so far...or does it? Try the following code at the bottom of the playground:

```vectorA • vectorB + vectorA // Error!
```

Xcode isn't very happy with you. But why?

Right now, `•` and `+` have the same precedence, so the compiler parses the expression from left to right. The compiler interprets your code as:

```(vectorA • vectorB) + vectorA
```

This expression boils down to `Int + Vector`, which you haven’t implemented and don't plan to implement. What can you do to fix this?

## Precedence Groups

All operators in Swift belong to a precedence group, which describes the order in which operators should be evaluated. Remember learning the order of operations in elementary school math? That is essentially what you're dealing with here.

In the Swift standard library, the order of precedence is as follows:

Here are a few notes about these operators, since you may not have seen them before:

1. Bitwise shift operators, `<<` and `>>`, are used for binary calculations.
2. You use casting operators, `is` and `as`, to determine or change a value's type.
3. The nil coalescing operator, `??`, helps providing a fallback value for optional values.
4. If your custom operator does not specify a precedence, `DefaultPrecedence` is automatically assigned.
5. The ternary operator, `? :`, is analogous to an if-else statement.
6. `AssignmentPrecedence`, for the derivatives of `=`, is evaluated after everything else, no matter what.

The compiler parses types that have a left associativity so that `v1 + v2 + v3 == (v1 + v2) + v3`. The opposite is true for right associativity.

Operators are parsed in the order they appear in the table. Try to rewrite the following code using parentheses:

```v1 + v2 * v3 / v4 * v5 == v6 - v7 / v8
```

When you're ready to check your math, look at the solution below.

[spoiler title="Solution"]

```(v1 + (((v2 * v3) / v4) * v5)) == (v6 - (v7 / v8))
```

[/spoiler]

In most cases, you'll want to add parentheses to make your code easier to read. Either way, it's useful to understand the order in which the compiler evaluates operators.

Owen L Brown

## Contributors

Owen L Brown

Author

Evan Dekhayser

Author

Bas Broek

Tech Editor

Illustrator

Final Pass Editor