Swift lazy subscript ignores filter

It comes down to subscripting a LazyFilterCollection with an integer which in this case ignores the predicate and forwards the subscript operation to the base.

For example, if we're looking for the strictly positive integers in an array :

let array = [-10, 10, 20, 30]
let lazyFilter = array.lazy.filter { $0 > 0 }

print(lazyFilter[3])                 // 30

Or, if we're looking for the lowercase characters in a string :

let str = "Hello"
let lazyFilter = str.lazy.filter { $0 > "Z" }

print(lazyFilter[str.startIndex])    //H

In both cases, the subscript is forwarded to the base collection.

The proper way of subscripting a LazyFilterCollection is using a LazyFilterCollection<Base>.Index as described in the documentation :

let start = lazyFilter.startIndex
let index = lazyFilter.index(start, offsetBy: 1)
print(lazyFilter[index])  

Which yields 20 for the array example, or l for the string example.


In your case, trying to access the index 3:

let start = empty.startIndex
let index = empty.index(start, offsetBy: 3)
print(empty)

would raise the expected runtime error :

Fatal error: Index out of range


To add to Carpsen90's answer, you run into one of Collection's particularities: it's not recommended, nor safe to access collections by an absolute index, even if the type system allows this. Because the collection you receive might be a subset of another one.

Let's take a simpler example, array slicing:

let array = [0, 1, 2, 3, 4]
let slice = array[2..<3]
print(slice) // [2]
print(slice.first) // Optional(2)
print(slice[0]) // crashes with array index out of bounds

Even if slice is a collection indexable by an integer, it's still unsafe to use absolute integers to access elements of that collection, as the collection might have a different set of indices.