Range in Swift: The elemental one

Shubham Bakshi
Apr 24 · 5 min read

Well, how many times have you used the code below

let myArray = [1,2,3,4,5,6,7,8,9,10]

Or , maybe , when someone asked you to fetch first five items from an array

var myModifiedArray = [Int]()for currentNumber in 0..<5 {
myModifiedArray.append(myArray[currentNumber])
}

Well, what if i tell you, you can do it in a better and cleaner way !

// Create an Array of first 10 elements 
var myArray = Array(1...10)
// Creating a new array with first five elements of previous array
let myModifiedArray = myArray[0…4]
Not bad, Right ?

There are 3 main categories for ranges —

  1. Closed Ranges : ClosedRange and CountableClosedRange
  2. Half-Open Ranges : Range and CountableRange
  3. One-Sided Ranges : PartialRangeUpTo , PartialRangeThrough and PartialRangeFrom

We can use .contains(anElement) on a range to check if certain element exists inside a range.

You might be wondering “ What’s the difference between a normal range and a countable one ? Isn’t a range supposed to be countable ? ” .

Hmmmmmm

A short answer would be, No ! And there’s a really good and logical explanation to it as well . I’ll explain that later in this article .

Closed Ranges

A Closed Range is a category which is essentially defined using an upper and lower bound and have (three dots) between the bounds . Both upper and lower bounds are included in the range.

ClosedRange and CountableClosedRange is essentially the same but in case of CountableClosedRange , the bound that you are specifying should conform to Strideable protocol and bound.stride should conform to SignedInteger which, in short, means we can only create CountableClosedRange with bounds like Int , Int8 , Int16, Int32, Int64 . And, you must be like “Wait, not even Double ? ” . Like I said, i’ll get back to that soon !

Half-Open Ranges

Half-Open range, which is represented by Range, is a category which is pretty much the same as Closed Range but differs in the fact that, first of all, is represented by ..<(two dots followed by less than operator) and it does not include the upper bound in the range.

CountableRange follows the same rules as explained earlier for CountableClosedRange.

One-Sided Ranges

One-Sided ranges only contains one bound and that too on one side of the range only (i.e. they can only contain either a lower or upper bound depending on the type) . One-Sided range can be represented by one of the following :

  • PartialRangeFrom : It only has a lower bound and is represented by lowerBound followed by … (three dots). It includes the lower bound
  • PartialRangeThrough : It only has an upper bound and is represented by … (three dots) followed by an upper bound. It includes the upper bound
  • PartialRangeUpTo : It only has an upper bound and is represented by ..< (two dots followed by less than operator) . It does not include the upper bound.

Now comes the part “ Why we cannot use Double as a bound for CountableRange and CountableClosedRange ” .

Well, first let me tell me you what i mean when i say the word Countable . For the moment just assume that it means you can iterate over it (using a for-in loop) .

Let’s first create a CountableClosedRange with bounds of type Int and iterate over it.

Splendid !

As we can see above, we can easily iterate over the range.

Now let’s change our bounds type to Double instead of an Int and see what happens.

Oops?

As soon as we try to change the bounds to a double value, we get an error. Even if we try to explicitly provide a CountableClosedRange<Double> , we still can’t get rid of that error, and this time, we get a new error !

Or, Even if we try to directly iterate over our Double range ,

This error is a bit more informative as it clearly states that a bound type to be CountableClosedRange , that bound has to conform to SignedInteger protocol which can be Int, Int8, Int16, Int32 or Int64. That clears out the fact that we can only use Int and not Double . But again, WHY ?

Consider this, if we have Int range and we traverse over it, the least number that we can iterate by is 1. Say, from 1…3 , we were traversing by 1 because that’s the least that we can go in Int. But, in case of 1.0…3.0 , the compiler does not know by what factor should we increment as here we can increment by 1,0.1,0.001,0.00001 and there can be infinite possibilities as all are doubles . And thus we cannot iterate over it . And so we cannot declare CountableClosedRange with bounds Double .

But , if you still want to iterate over a Double range in a for-in loop , you can make use of stride(from:to:by:) or stride(from:through:by:) (this overloaded method includes the upper bound) in which the by: parameter defines by what factor you want to increment in each iteration.

Well, that’s it from my side !

You can connect with me on LinkedIn 👱🏻 or can get in touch with me via other channels 📬

Shubham Bakshi

Written by

iOS Engineer | Motivational Speaker enthusiast

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade