Common Swift Operators You May Not Know About

Even though most operators in Swift look and behave the same way they do in other programming languages, there are a few you may not know about or that behave in a slightly different manner.

Ternary Conditional Operator

If you have any experience programming, then you probably know about the ternary conditional operator. In Swift, the behavior of this operator is identical to that in C and Objective-C.

This operator is often used to replace simple if-else statements. In the example below, the result of the assignment that uses the ternary conditional operator is identical to that of the if-else statement. I am sure you agree that the example that uses the ternary conditional operator is more elegant and easier to read.

var message = ""
let price = 10.0

if price > 20.0 {
    message = "expensive"
} else {
    message = "bargain"
}

message = price > 20.0 ? "expensive" : "bargain"

Nil Coalescing

The nil coalescing operator does not exist in C and Objective-C. The idea is simple, though. Take a look at the following example.

var a: Int?
var b = 5

let c = a ?? b

The ?? or nil coalescing operator inspects the value of a. If a has no value, it defaults to the value stored in b. In the above example, c is assigned the value of 5.

What I like about the ?? operator in Swift is that it implicitly unwraps an optional and only assigns a value if the optional has a value. The above example shows how that works.

Range Operators

Swift defines two range operators:

  • ... or closed range operator
  • ..< or half-open range operator

The difference is obvious as illustrated by the example below. The body of the first for-in loop is executed eleven times whereas that of the second for-in loop is executed only ten times.

for i in 0...10 {
    print(i)
}

for i in 0..<10 {
    print(i)
}

The ... or closed range operator includes the final value of the range whereas the ..< or half-open operator excludes the final value of the range.

Range operators are very useful for looping over a range of values. But why does Swift define two range operators? This is primarily for convenience. Take a look at the following example.

let numbers = [49, 27, 4, 32, 23, 431, 5]

for i in 0..<(numbers.count) {
    print(numbers[i])
}

The example is somewhat contrived because there are better ways to enumerate the values of an array. The point is that half-open range operators are convenient for looping over collections that are zero-based, such as arrays.

Equality & Identity Operators

Chances are that you are already familiar with Swift's equality operators, == and !=. But Swift also defines a pair of identity operators, === and !==. Take a look the next example to learn about the differences.

let arr1 = NSArray(array: [1, 2])
let arr2 = NSArray(array: [1, 2])
let arr3 = arr2

print(arr1 == arr2)  // true
print(arr1 === arr2) // false
print(arr2 === arr3) // true

The == or equality operator checks whether the two operands are equal. What equal means for an object depends on the implementation of the class or structure. For the NSArray class, the contents of the arrays are compared. In the above example, arr1 is equal to arr2 because the values stored in the arrays are equal.

The === or identity operator compares the identity of the objects. It checks whether the operands refer to the same object. As you can see, arr1 and arr2 do not refer to the same object, despite the objects being equal. The identity of arr2 and arr3 is the same, though. Both constants point to the same object.

Subscript Syntax

Even though the term subscript may sound foreign to you, chances are that you have already used Swift's subscript syntax. Take a look at the next example to learn what subscript syntax looks like in Swift.

let cities = ["New York", "Paris", "Berlin", "London"]

print(cities[2])

The [] or subscript syntax should look familiar if you have worked with arrays and dictionaries. The reason I bring it up is to show you how to use it in custom classes and structures.

Take a look at the following example in which we define the Item and ShoppingList structures. To add support for subscript syntax to the ShoppingList structure, we write a subscript definition using the subscript keyword. This enables us to query ShoppingList instances using subscript syntax. Note that we do not use the func keyword when creating a subscript definition.

struct Item {

    var price = 0.0
    var name: String

    init(name: String) {
        self.name = name
    }

}

struct ShoppingList {

    var items = [Item]()

    mutating func addItem(item: Item) {
        items.append(item)
    }

    subscript(index: Int) -> Item? {
        return (index < items.count) ? items[index] : nil
    }

}

This implementation allows us to use subscript syntax on instances of the ShoppingList structure.

var shoppingList = ShoppingList()

if let item = shoppingList[0] {
    print(item.name)
} else {
    print("No Item Found")
}

shoppingList.addItem(Item(name: "Milk"))

if let item = shoppingList[0] {
    print(item.name)
} else {
    print("No Item Found")
}

The subscript definition in the above example accepts a value of type Int. If you want subscript syntax for the ShoppingList class to work with String values as well, then you need to create another subscript definition. That is how the Dictionary structure, defined in the Swift Standard Library, adds support for subscript syntax.

What's Next?

The Swift programming language defines a wide range of operators. Most of them are pretty easy to understand, but Swift also defines a slew of pretty advanced operators. If you want to learn more about operators in Swift, I recommend taking a look at the language reference for basic operators and advanced operators.

Questions? Leave them in the comments below or reach out to me on Twitter.