Custom operators in Swift can make your code easier to read and simpler to maintain. Code can be written less lines of code while keeping it clear what is happening. Custom operators are also known as advanced operators and allow you to combine two instances with a self-chosen infix, prefix, postfix, or assignment operator.
When developing code in Swift we’re all using the default operators quite often. Adding up two numbers by using the +
sign is an example of making use of basic operators available in Swift. Let’s dive in and see how you can improve your code with custom-defined operators.
Examples of basic operators available in Swift
To fully understand what operators are we can go over a few operator examples that are available in Swift by default. Some might be more obvious to you than others!
For example, the assignment operator is very often used (obviously) but is also an operator!
/// Assignment `=` operator example.
let name = "Antoine"
let age = 29
There are a few so-called Unary operators like the unary prefix operator !value
and the unary postfix operator value!
, also known as the force unwrap operator
/// Unary postfix `!` operator example.
let forceUnwrappedURL: URL = URL(string: "www.avanderlee.com")!
/// Unary prefix `!` operator example.
let URLHasValue = !forceUnwrappedURL.absoluteString.isEmpty
A common example of an infix operator is the +
sign which falls under the category Binary operators. It’s called an infix operator as it appears in between two values.
/// Infix operator `+` example.
let totalSum = 10 + 4
Swift also comes with a Ternary operator the operates on three targets. The ternary conditional operator allows us to write if statements in a single line:
/// Ternary operator example `?:`, the ternary conditional operator.
let title = page.hasTitle ? page.title : "Untitled"
These are all just a few examples of all available operators in Swift. You can read more about the basic operators in the Swift Language Guide.
Creating a custom operator
A custom operator can be created by defining a static method in an extension of the type you want to work with. There are a few different operators as described before that you can choose to define. Let’s go over a few practical examples that you can use in your codebase.
Creating a custom compound assignment operator
Compound assignment operators combine assignment (=) with another operator. This is the kind of operator that is often customized as it’s easier to think of use-case examples.
Take the following example in which we have a team full of members:
struct Team {
let title: String
private(set) var members: [Member]
mutating func add(_ member: Member) {
members.append(member)
}
}
struct Member {
let name: String
}
This code allows us to write the following code by making use of the add(_:)
method:
var team = Team(title: "Developers", members: [Member(name: "Antoine")])
let newMember = Member(name: "Boris")
team.add(newMember)
We can swap this code for an operator that allows us to add members directly to the team by making use of the +=
operator:
extension Team {
static func += (lhs: inout Team, rhs: Member) {
lhs.add(rhs)
}
}
Let’s go through this code step by step:
- First, we make an extension on our
Team
structure - The operator is defined as a static method in which the method name defines the operator
- As we’re working with structs we need to use
inout
which adds the requirement of having a mutableTeam
instance - Finally, we’re passing in the new member which we can add to the team with the
add(_:)
method
We can make use of this operator as follows:
let newMember = Member(name: "Boris")
team += newMember
Prefix and postfix operators
Prefix and Postfix operators might be less commonly used as custom operators. It’s a bit a different mindset when thinking about use-case examples. However, there are quite a few nice things you can do with them.
In this example, we’re going to define a prefix operator. However, you could define postfix operators in the same way.
Take the following code example in which we convert a decimal number into a String
with the right currency based on the current locale:
let currencyFormatter = NumberFormatter()
currencyFormatter.numberStyle = .currency
currencyFormatter.locale = Locale.current
let priceString = currencyFormatter.string(from: 9999.99)!
// Displays $9,999.99 in the current locale, for example $ dollars.
print(priceString)
It’s likely that we will have to convert a lot of our values into currency strings so it would be great if can shorten this code. We can do this by introducing a self-named Currency operator that transforms a given decimal into a string with the currency applied.
prefix func ~ (value: NSNumber) -> String {
let currencyFormatter = NumberFormatter()
currencyFormatter.numberStyle = .currency
currencyFormatter.locale = Locale.current
return currencyFormatter.string(from: value)!
}
There are a few things to consider when reading through this defined prefix operator:
- The operator is globally defined and not tight to a specific type. This is required as we’re only working with the argument value and we don’t have a receiver type that we would otherwise define in the extension
- We take a
NSNumber
as an input argument. This allows us to use the operator on any number type. - Note that we convert an input number into an output string. This should open your eyes to other use-cases!
You can use this custom operator as follows:
let decimalInputPrice: String = ~843.32
print(decimalInputPrice) // Prints: $843.32
let intInputPrice: String = ~300
print(intInputPrice) // Prints: $300.00
This can improve the readability of your code! However, you need to tell your colleagues about the newly introduced ~
Currency operator so they also understand what is going on.
Custom Infix Operator
Infix operators are a bit more complicated and require to set a precedence group. This group is required for Swift to know which of the operators should be executed first, in case of having multiple operators in one statement. You can find all available operators and their precedence groups on Apple’s Operator Declarations page.
An example of an infix operator can look as follows:
infix operator +-: AdditionPrecedence
extension Set {
static func +- (lhs: Set, rhs: Set) -> Set {
return lhs.union(rhs)
}
}
This infix operator will take two sets as input and outputs a set with all unique numbers. An example implementation looks as follows:
let firstNumbers: Set<Int> = [1, 4, 5]
let secondNumbers: Set<Int> = [1, 4, 6]
let uniqueNumbers = firstNumbers +- secondNumbers
print(uniqueNumbers) // Prints: [1, 4, 5, 6]
Calculating with Emojis in Swift
I never thought that I would write about emoji calculation in Swift but it turned out to be a popular April fools joke in 2020.
Many thought that I used Photoshop to create the outcome but the fact is, it was actually all working for real!
You could know this from the line numbers on the left and the green +
operator sign in the image used:
Now that you know how you can create your own custom operators it’s a nice practice to try and build this for yourself. However, you can also simply take a look at the code as follows:
extension String {
static func + (lhs: String, rhs: String) -> String {
switch (lhs, rhs) {
case ("πΉ", "βοΈ"):
return "π"
case ("π¬", "βοΈ"):
return "π₯Ά"
case ("π’", "π₯"):
return "π₯΅"
case ("π₯", "π₯¬"):
return "π₯¬"
case ("π₯¬", "π₯"):
return "π₯"
case ("π₯", "π
"):
return "π₯"
case ("π§", "π"):
return "πΆπ»"
case ("π¦", "π"):
return "π¦"
case ("π¨", "π§"):
return "π "
default:
print("\(lhs) and \(rhs) not matched")
return "βοΈ"
}
}
}
As you can see, it’s simply a custom infix operator on strings that allows you to “calculate” with different emojis. You can now try it out for yourself and start adding your own combinations of which I would obviously love to hear from you which combination you created!
Custom Operators Playground
All operators in this blog post are demonstrated in my Custom Operators Playground which you can find on GitHub. Feel free to play around and add your custom operators if you want.
Conclusion
Custom operators in Swift can help you to reduce duplicate code and improve the readability. You can consider creating infix, prefix, postfix, or assignment operators that work for your use-case. The above practical examples show how you can add operators to your own custom defined types.
Not getting enough out of this? How about defining your own custom subscripts in Swift.
If you like to improve your Swift knowledge, even more, check out the Swift category page. Feel free to contact me or tweet to me on Twitter if you have any additional tips or feedback.
Thanks!