A discussion in the "mapValues" thread reminded me of a longstanding issue I 
have with Swift.

`enumerate()` is an attractive nuisance. (That is, it looks like the thing you 
want, but it's not actually the right one.) Most people use it because they 
want to enumerate over indices and elements at the same time. In reality, 
though, the first element of an `enumerate()` tuple is not the index—it's a 
monotonically increasing integer starting at 0. That *happens* to work for 
`Array`:

>         1>     let array = Array(0..<10) 
>         2.     for (i, elem) in array.enumerate() { 
>         3.         print(array[i]) 
>         4.     }
>       0
>       1
>       2
>       3
>       4
>       5
>       6
>       7
>       8
>       9

But if you stray even a little bit from the golden path, things start to go 
wrong:

>         5>     let range = array[2..<8]
>         6.     for (i, elem) in range.enumerate() { 
>         7.         print(range[i])
>         8.     } 
>       fatal error: Index out of bounds

You can scarcely blame users for making this mistake, though—"The Swift 
Programming Language" encourages the misconception. "Iterating Over an Array" 
in "Collection Types":

> If you need the integer index of each item as well as its value, use the 
> `enumerate()` method to iterate over the array instead. For each item in the 
> array, the `enumerate()` method returns a tuple composed of the index and the 
> value for that item.


While the text is technically accurate—it only talks about iterating over 
arrays and the numbers generated by `enumerate()` happen to correspond to array 
indices—it creates a false implication that `enumerate()` is defined to return 
indices, which isn't true of other collections.

This is made worse by the fact that `enumerate()` is not really a good name. It 
is not a common word, so people don't read it and immediately understand what 
it does; they memorize a Swift-specific meaning, and that meaning may 
incorporate the misconception that `enumerate()` includes indices. It is also 
not technically accurate: although it has "number" in its Latin roots, 
"enumerate" means either "to count" or "to list", not "to number" (i.e. assign 
numbers to). I know `enumerate()` is used in a couple of other languages 
(certainly Python, possibly others), but I don't think that overrides the fact 
that it's confusing.

I have three possible solutions to propose.



OPTION ONE

* Remove `enumerate()`.

* Provide a type and postfix operator which allows you to write an infinite 
sequence as `0...`. (This might call a ClosedRange constructor which constrains 
the type to a protocol which provides `max`. This would imply that 
`FloatingPoint` and `Integer` protocols would need to conform to a common 
protocol declaring a `max` property, and in the case of `FloatingPoint`, `max` 
should probably be positive infinity.)

* Fix-It calls to `x.enumerate()` as `zip(0..., x)`. This is more complicated 
to look at, but it's *far* more explicit about what the operation actually 
does. (For bonus points, we could perhaps look at how the EnumerateSequence is 
used, and if the number is used as an index, go with `zip(x.indices, x)` 
instead.)



OPTION TWO

* Rename `enumerate()` to something more explicit, like `withIntegers()` or 
`numbered()`. (It might even make sense to add a `from:` parameter which 
defaults to 0.)

* Add to Collection an equivalent method with a similar name that provides 
indices, like `withIndices()` or `indexed()`.

* Fix-It calls to `enumerate()` into either `numbered()` or `indexed()` (or 
whatever they end up being called) depending on the way they are used.



OPTION THREE

Combine the other two options:

* Provide the infinite numeric sequence type from Option One.

* Provide `numbered()` and `indexed()` (or whatever) methods which are 
explicitly typed to merely zip over the sequence/collection with an infinite 
integer sequence/Indices collection.

-- 
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to