Smarter Numbers. Annex 1: Custom operators.

On my earlier post, “Smarter Numbers”, we talked about using operator overrides in swift to extend the functionality of framework classes.

There’s a bit more to it than what was discussed in the article, but we’ve decided to keep it as a separate post due it’s less “orthodox” usage: Swift also allows you to, in what could be considered as a controversial feature, create custom operators. This means that not only can you change the behaviour of the language. you can also change the language itself*.

Ok, so… Suppose we have our NSNumber extension class from our previous article. And we wanted to use custom operators to replace the usage of our “power of” and “root of” functions. Currently we have the following functions specified:


func powerOf(number : NSNumber) -> NSNumber {
  return NSNumber(double:pow(self.doubleValue, number.doubleValue))
}

func rootOf(number : NSNumber) -> NSNumber {
  return NSNumber(double:pow(self.doubleValue, 1/number.doubleValue))
}

Now instead of having functions to do our jobs, we wanted the custom operators “^”**  and “√”***. Unfortunately for us, the operator “^” is already used in swift as a bitwise XOR operator, which makes us not want to override it for two reasons:

  • We would be working against the default language behaviour.
  • Changing the default behaviour could lead to bad things.

So we’re going to have to get a bit creative here. For the purposes of this article, I will be replacing the usage of  “^” with the next best symbol I could think of: “°”****. Note that you could also chain symbols, like “^*” or “^/” if you wanted to, which would make the symbols more accessible for developers working with keyboards in different languages.

Once we’ve picked symbols that make sense, we write down our functions in a very similar way to what we wrote for an operator override, except now we have to declare our operators before the function:


//custom "power of"
infix operator ° { associativity left precedence 150 }
func ° (left:NSNumber, right:NSNumber) -> NSNumber {
  return NSNumber(double:pow(left.doubleValue, right.doubleValue))
}

//custom "root of"
infix operator √ { associativity left precedence 150 }
func √ (left:NSNumber, right:NSNumber) -> NSNumber {
  return NSNumber(double:pow(left.doubleValue, 1/right.doubleValue))
}

Now we can exchange our implementations of:


let number : NSNumber = 10
let power = number.powerOf(3)
let root = number.rootOf(4)

For our custom implementations:


let number : NSNumber = 10
let power = number°3
let root = number√4

As you can see, it’s very debatable how much advantage our custom operators have over our previous functions, and honestly, I can personally see none, as our previous functions are a lot easier to read and less “unexpected”. But I’m hoping this article might help other developers find a better, and more robust usage for this feature.

One thing we need to consider, though, is operator precedence and associativity. These rules are responsible for establishing the order in which operators should be processed, and it’s what ensures that multiplications are processed before additions, in a statement such as:  2 + 2 * 2.

A higher associativity value will process the result of your operator before lower associativity values, and precedence establishes if the calculation is prioritized from the left or the right operator. A full list of default swift operators can be found here.

Hopefully this little side post will enlighten developers on the usage and pitfalls of custom Swift operators. Now that you’ve learned a bit about the dark side of Swift and (hopefully) found it interesting, forget you’ve ever read this and Code ON!


*Admittedly, as much as I love the flexibility this allows, I have yet to find a valid use for this feature. Using this will means that you’ll be changing the framework behaviour for other developers that have to pick up on the project too, so you should probably avoid using this on production apps unless your team has very strict and well-known conventions and an arguably “good” reason to use this (and the operators you use are blatantly obvious).

** Shift + ‘6’ on international english keyboards.

***Alt + ‘v’ on international english keyboards.

****Alt + Shift + ‘8’ on international english keyboards. I know, I know… It’s a bit of a regrettable choice. 😀

Author: Danny Bravo

Director @ EPIC