[swift-evolution] [Pitch] Enumerate from offset

Pavol Vaskovic pali at pali.sk
Thu May 4 07:39:02 CDT 2017


Here's a pitch to pick a small nit from the Sequence protocol:


Best regards
Pavol Vaskovic

Enumerate from offset


   Proposal: SE-NNNN

   Authors: Pavol Vaskovic <https://github.com/palimondo>, Author 2

   Review Manager: TBD

   Status: Pitch

   Bugs: SR-4746 <https://bugs.swift.org/browse/SR-4746>


Let user specify the staring index for enumerated method on Sequences.

Swift-evolution thread: Discussion thread topic for that proposal

The enumerated() method defined in an extension on protocol Sequence always
counts from 0. When you need the numbers to be counting up from different
index, you have to post process the resulting tuple in an inconvenient way.

We could provide an option to count elements from a user specified offset:

[6, 7, 8].enumerated(from: 6)// [(offset: 6, element: 6), (offset: 7,
element: 7), (offset: 8, element: 8)]

If implemented with default parameter, this does not change the usage for
existing code, being source compatible with Swift 3.

The proposed solution is to propagate the starting value to the internal
counter on EnumeratedIterator and set the default starting value to 0.

public struct EnumeratedIterator<
    Base : IteratorProtocol> : IteratorProtocol, Sequence {
    internal var _base: Base
    internal var _count: Int

    /// Construct from a `Base` iterator.    internal init(_base:
Base, _offset: Int) {
        self._base = _base
        self._count = _offset

    /// The type of element returned by `next()`.    public typealias
Element = (offset: Int, element: Base.Element)

    /// Advances to the next element and returns it, or `nil` if no
next element    /// exists.    ///    /// Once `nil` has been
returned, all subsequent calls return `nil`.    public mutating func
next() -> Element? {
        guard let b = _base.next() else { return nil }
        let result = (offset: _count, element: b)
        _count += 1
        return result
public struct EnumeratedSequence<Base : Sequence> : Sequence {
    internal var _base: Base
    internal let _offset: Int

    /// Construct from a `Base` sequence.    internal init(_base:
Base, _offset: Int) {
        self._base = _base
        self._offset = _offset

    /// Returns an iterator over the elements of this sequence.
public func makeIterator() -> _EnumeratedIterator<Base.Iterator> {
        return EnumeratedIterator(_base: _base.makeIterator(), _offset: _offset)
extension Sequence {
    public func enumerated(from: Int = 0) -> _numeratedSequence<Self> {
        return EnumeratedSequence(_base: self, _offset: from)


Proposed change is source compatible with Swift 3.
on ABI stability and resilience

This change does affect the ABI and should be implemented before we freeze

Currently proposed workaround for the lack of flexibility in enumerated() is
to use zip with the collection and half-open range. From SR-0172 One-sided

Additionally, when the index is a countable type, i... should form a
Sequence that counts up from i indefinitely. This is useful in forming
variants of Sequence.enumerated() when you either want them non-zero-based
i.e.zip(1..., greeting), or want to flip the order i.e. zip(greeting, 0...).

Drawback of this approach is that you need to use free function zip,
forcing a break in the chain of sequence operations, as there is currently
no zipped method on Sequence.

If this is the preffered approach, we should consider removing the
enumerated() method altogether, because the limited usefullness in its
current state hardly justifies the space on API surface it occupies.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170504/408a2b61/attachment.html>

More information about the swift-evolution mailing list