[swift-evolution] [Pitch] Enumerate from offset

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


Hello!

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

https://github.com/palimondo/swift-evolution/blob/sequence-cleanup/proposals/NNNN-enumerate-from.md

Best regards
Pavol Vaskovic

Enumerate from offset

   -

   Proposal: SE-NNNN
   <https://github.com/palimondo/swift-evolution/blob/sequence-cleanup/proposals/NNNN-enumerate-from.md>
   -

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

   Review Manager: TBD
   -

   Status: Pitch
   -

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

<https://github.com/palimondo/swift-evolution/blob/sequence-cleanup/proposals/NNNN-enumerate-from.md#introduction>
Introduction

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

Swift-evolution thread: Discussion thread topic for that proposal
<https://lists.swift.org/pipermail/swift-evolution/>
<https://github.com/palimondo/swift-evolution/blob/sequence-cleanup/proposals/NNNN-enumerate-from.md#motivation>
Motivation

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.
<https://github.com/palimondo/swift-evolution/blob/sequence-cleanup/proposals/NNNN-enumerate-from.md#proposed-solution>Proposed
solution

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.
<https://github.com/palimondo/swift-evolution/blob/sequence-cleanup/proposals/NNNN-enumerate-from.md#detailed-design>Detailed
design

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)
    }
}

<https://github.com/palimondo/swift-evolution/blob/sequence-cleanup/proposals/NNNN-enumerate-from.md#source-compatibility>Source
compatibility

Proposed change is source compatible with Swift 3.
<https://github.com/palimondo/swift-evolution/blob/sequence-cleanup/proposals/NNNN-enumerate-from.md#effect-on-abi-stability-and-resilience>Effect
on ABI stability and resilience

This change does affect the ABI and should be implemented before we freeze
it.
<https://github.com/palimondo/swift-evolution/blob/sequence-cleanup/proposals/NNNN-enumerate-from.md#alternatives-considered>Alternatives
considered

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
Ranges
<https://github.com/apple/swift-evolution/blob/master/proposals/0172-one-sided-ranges.md>
:

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