How to create a custom operator (like ~= operator) in swift ?? — 🤓🤓🤓🤓

I have seen developers using custom operators which adds meaning to the code and reduce the amount of code required to perform an operation. Creating custom operators are not encouraged. But you still can, if you wish to!!.

Abhimuralidharan
5 min readMay 11, 2018

--

I was learning about pattern matching in swift and my eyes got stuck on a special operator ~= . I have used this before for pattern matching, But I didn’t knew how it works. I have used ~= operator for checking if the http error fall into any of the given range (wanted to check if error is 4xx excluding 401) like this:

I didn’t had any idea what it does internally. I also didn’t knew that we can also create custom operators like this. So, I asked google about this and he showed me all what I wanted.

Have a look at some of such operators in swift: Defines Swift

Types of Operators

Operators in swift fall into the following types:

  • Infix — Used between two values (ex: <value>+<value>)
  • Prefix — Used before a value (ex: !<value>)
  • Postfix — Used after a value (ex: <value>!)
  • Ternary — Two symbols inserted between three values(ex: <value1> ?<value2> :<value3>). We cannot create custom ternary operators as of now. Swift won’t allow developers to do this.

How to create Custom Operators??

Let’s create a custom operator for finding the square root of a number using the symbol.

Note: We already have the sqrt() function to find the square root and is easy to use. Consider this as a simple example to create custom operators🤓🤓 .

We should be using this as a prefix operator like:

let someVal = 25let squareRoot = someVal // result is 5

Let’s discuss the steps to create one.

  • We need to declare this symbol as a prefix operator.
prefix operator √
  • We need to create a function which accepts one parameter and perform the operation (square root).
prefix func √(lhs: Double) -> Double {return sqrt(lhs)}

DONE!! — — — Congrats!!. You just created a custom prefix operator to find the square root.

Custom square root operator in swift

Let us create a custom infix operator using ◉ symbol.

The ◉ operator function will accept two values lhs and rhs and return the sum of squares of these values. ie; if lhs is 2 and rhs is 3, the result will be 4 + 9. ie; 13.

If you remember the steps,

  • We need to declare this ◉ symbol as a infix operator.
infix operator ◉
  • We need to create a function which accepts two parameters and perform the operation explained above.
infix func ◉(lhs: Double, rhs: Double) -> Double {return lhs * lhs + rhs * rhs}

If you do this, the compiler will yell at you saying: error: MyPlayground.playground:14:1: error: ‘infix’ modifier is not required or allowed on func declarations

So, rewrite the function by removing the infix keyword.

 func ◉(lhs: Double, rhs: Double) -> Double {return lhs * lhs + rhs * rhs}

Congrats. You just created a custom infix operator. But wait. Is that it??🤨🤨

Question: Is that it? Do we have to consider anything else while creating a custom operator??🤔🤔🤔🤔

Answer: YES 😱😱😱 !!!.. Almost forgot the operator precedence that we learned in school.

Refer pages: Order of operations,Operator declarations.

In mathematics and most computer languages, multiplication is granted a higher precedence than addition. Thus, the expression 2 + 3 × 4 is interpreted to have the value 2 + (3 × 4) = 14, not (2 + 3) × 4 = 20. We will have to consider this as well while creating a custom operator. The operators precedence is an important factor.

Precedence and Associativity

Apple Docs Link here.

Operator precedence gives some operators higher priority than others; these operators are applied first.

Operator associativity defines how operators of the same precedence are grouped together — either grouped from the left, or grouped from the right. Think of it as meaning “they associate with the expression to their left,” or “they associate with the expression to their right.”

Types that have a left associativity are parsed so that v1 + v2 + v3 == (v1 + v2) + v3. The opposite is true for right associativity.

If you declare a new operator without specifying a precedence group, it is a member of the DefaultPrecedence precedence group. DefaultPrecedence has no associativity and a precedence immediately higher than TernaryPrecedence.

Source: raywenderlich

Refer Apple docs to get the entire list of operators used in swift with their details.

Coming back to our ◉ infix operator, It doesn’t fit to any of the standard precedence groups. We will have to create our own. How to do that?

  • Create a precedence group called SquareSumOperatorPrecedence.
precedencegroup SquareSumOperatorPrecedence {lowerThan: MultiplicationPrecedencehigherThan: AdditionPrecedenceassociativity: leftassignment: false}

Here, we created a precedence group with precedence higher than AdditionPrecedence and lower than MultiplicationPrecedence and left associativity.

‘none’, ‘left’, or ‘right’ are the possible values for associativity.

The assignment modifier that works as follows: an operator marked assignment gets folded into an optional chain, allowing foo?.bar += 2 to work as foo?(.bar += 2) instead of failing to type-check as (foo?.bar) += 2.

This behaviour will be passed to assignment: true on precedence groups.

  • Now replace your original declaration of the ◉ operator with the following:
infix operator ◉: SquareSumOperatorPrecedence

That’s it.

custom infix operator

That’s it. !

Where to go from here?

  • Learn about operator overloading.Classes and structures can provide their own implementations of existing operators. This is known as overloading the existing operators. Ex: == , + etc..
Example from apple docs
  • Learn more about adding generic type constraints to custom operators

Enjoy!!

If you enjoyed reading this post, please share and give some clapps so others can find it 👏👏👏👏👏 !!!!

You can follow me on Medium for fresh articles. Also, connect with me on LinkedIn and Twitter.

If you have any comment, question, or recommendation, feel free to post them in the comment section below!

--

--