Skip to main content

How to Work with One-sided Ranges in Swift 4

Tags

How to Work with One Sided Ranges in Swift 4

One of the nice new feature enhancements in Swift 4 this year is Proposal 172 for One-sided Ranges. Proposal 172, in Swift Evolution, now simplifies collection manipulation by giving developers the option to pick from using the verbosity of the start and endIndex or using the newly implemented syntax that infers the start and end index for you.  The major motivation for this proposal was the accumulated verbosity that can come from slicing up many different forms of a single collection and the pure code surface area that it took to perform these actions.  This code surface area was thought to be too dense, and at some times hard to read.  From the motivation to reduce this surface area, proposal 172 is now giving developers the option to use the Pythonic inferred range syntax that gives developers the option be less or more verbose based upon their current situation. 

To further describe this situation, possibly one scenario requires you to at define a range from a random index to the end of a string.  And then from that substring, cut out a smaller piece of that first substring.  At this point your code surface area has grown significantly because you are defining two ranges.  In Swift 3, you needed to use the verbosity of the endIndex to accomplish this range definition.  Now, for that first substring manipulation, you are given the option to use the inferred range syntax from you index and then with three dots; string[i...].  The three dots, or the sequence notation, lets Swift know that we want to start at an index and create a range to the end of the string.

NOTE:  This tutorial assumes you have at least Swift 4.0 installed in your Xcode toolchain or that you are using a version of Xcode that supports Swift 4, like Xcode 9 beta.  To get started with this tutorial you can know a lot about Swift or a little about Swift, these examples are aimed at everyone.

 

Swift 3 Ranges

In Swift 3, the foundation was really set for collection manipulation by providing developers the ability extract ranges using the sequence syntax. This improvement to collection manipulation made it easier to extract ranges between two indices simply defining a start and endIndex.  Swift 3 also provided developers the ability to user the less-than (<) and greater-than (>) operators to identify which side of a collection needed to be manipulated. 

For example, the following code snippet would allow developers to extract the substring, "Hello" by capturing everything from the startIndex of the collection to the index of the comma.

let s = "Hello, World!"
let i = s.index(of: ",")!
let greeting = s[s.startIndex..<i]

 

Swift 4 Ranges

Capturing a range from a collection in Swift 3 using this method works well, but in proposal 172 now there is an easier method when working with ranges that does not force developers to use the verbosity of the upper or lower index explicitly.  Instead, these bounds in a collection can be inferred for you.  For example, take a look at this code snippet:

//: Playground - noun: a place where people can play
 
import UIKit
// Swift 4 information
// https://github.com/apple/swift-evolution/blob/master/proposals/0172-one-sided-ranges.md
 
extension String: LocalizedError {
    public var errorDescription: String? { return self }
}
 
var str = "Hello, One-sided Ranges!"
guard let i = str.index(of: ",") else {
    throw "Not safe to continue on! 😎"
}
 
// ###### Start Index Inferred ######
 
// First slice with new range implementation for Swift 4, a lot less verbose
let firstSliceWithComma = str[...i] // Hello, -  a lot less verbose
let firstSliceUptoComma = str[..<i] // Hello -  a lot less verbose
 
// Swift 3 implementation, very similar, but on two lines
let firstSliceRangeUptoComma = str.startIndex..<i
str[firstSliceRangeUptoComma] // Hello
 
// or
 
str[str.startIndex..<i] // Hello -  a lot more verbose
 
let firstSliceRangeWithComma = str.startIndex...i
str[firstSliceRangeWithComma] // Hello,
 
// or
 
str[str.startIndex...i] // Hello, -  a lot more verbose
 
// ###### End Index Inferred ######
 
// Second slice with new range implementation for Swift 4
let secondSliceWithComma = str[i...] //, One-sided Ranges!
 
// Swift 3 implementation, very similar, but on two lines
let secondSliceRangeWithComma = i..<str.endIndex
str[secondSliceRangeWithComma]

The following code above is performing the same actions, but just using a mix of Swift 3 and Swift 4 syntax.  The major difference to identify is the usage of str[str.startIndex...i] or the usage of str[...i].  This is the new syntax improvement for proposal 172 in a nutshell.  This improvement allows developers to know be as verbose or concise as they want to be depending upon their scenario.   

I think this is a great improvement to the Swift language and will result in a lot less code overhead moving forward in large projects, especially where string manipulation is crucial.

Now you know more about how to work with One-sided ranges in Swift 4!  Please feel free to download the playground example from my Github and mess around with it.  One thing to note again is that if your version of Xcode does not support Swift 4 yet, you will need to download the Swift 4 toolchain to run this playground in Xcode.

Thank you very much for reading!

Credits: Cover image designed by Freepik.

Member for

3 years 9 months
Matt Eaton

Long time mobile team lead with a love for network engineering, security, IoT, oss, writing, wireless, and mobile.  Avid runner and determined health nut living in the greater Chicagoland area.