Draft here: https://gist.github.com/erica/a51a981ee0352235204692affa959307 
<https://gist.github.com/erica/a51a981ee0352235204692affa959307>  Feedback 
solicited, both positive and negative. 
We've also got a related proposal about expanding ranges, which you can look at 
here (https://gist.github.com/erica/af92c541a0fb69fce1b7aaf8374a5aa9 
<https://gist.github.com/erica/af92c541a0fb69fce1b7aaf8374a5aa9>)
 but we want to float this one first.

Thanks, -- E



Proposal: SE-XXXX 
<https://gist.github.com/erica/a51a981ee0352235204692affa959307/edit>
Author(s): Xiaodi Wu <https://github.com/xwu>, Pyry Jahkola 
<http://github.com/pyrtsa>, Nate Cook <http://github.com/natecook1000>, Erica 
Sadun <http://github.com/erica>
Status: TBD
Review manager: TBD
 
<https://gist.github.com/erica/a51a981ee0352235204692affa959307#introduction>Introduction

We propose to introduce a striding(by:) method on the revised 3.0 Range type.

This proposal was discussed on the Swift Evolution list in the Feature 
proposal: Range operator with step 
<http://search.gmane.org/search.php?group=gmane.comp.lang.swift.evolution&query=Feature+proposal%3A+Range+operator+with+step>
 thread. (Direct link 
<http://thread.gmane.org/gmane.comp.lang.swift.evolution/12801/focus=13051> to 
original thread)

 
<https://gist.github.com/erica/a51a981ee0352235204692affa959307#motivation>Motivation

Updating Range for Swift 3 offers a window of opportunity to simultaneously 
improve strides.

Under current Swift 3 plans, n.stride(to:/through:, by:) will be replaced with 
a standalone stride(from:, to:/through:, by:) function. We propose to replace 
this change with a method on ranges. Using a method reduces overall API surface 
area compared to free functions.

In its current incarnation, the standalone stride function uses confusing 
semantics. The current to implementation returns values in [start, end) and 
will never reach or get to end. The current through implementation returns 
values in [start, end]. It may never reach end and certainly never goes through 
that value. Our proposed method introduces simple, expected semantics that can 
be extended to both countable and continuous ranges, and to open and closed 
intervals (both half-open and fully-open).

 
<https://gist.github.com/erica/a51a981ee0352235204692affa959307#detail-design>Detail
 Design

The striding(by:) method is called on ranges. When used with a positive step 
size, the count starts from the lower bound. With a negative step size, the 
count starts from the upper bound. These bounds apply regardless of whether 
they are inclusive or exclusive. 

The following examples should cover all corner cases and include possible cases 
should Swift 3 introduce a full complement of open and closed ranges. The 
syntax for non-canonical range types is not fixed and can be discussed under 
separate cover.

(0 ... 9).striding(by: 2) == [0, 2, 4, 6, 8]
(0 ..< 9).striding(by: 2) == [0, 2, 4, 6, 8]
(0 <.. 9).striding(by: 2) ==    [2, 4, 6, 8]
(0 <.< 9).striding(by: 2) ==    [2, 4, 6, 8]

(0 ... 9).striding(by: 3) == [0, 3, 6, 9]
(0 ..< 9).striding(by: 3) == [0, 3, 6]
(0 <.. 9).striding(by: 3) ==    [3, 6, 9]
(0 <.< 9).striding(by: 3) ==    [3, 6]

(0 ... 9).striding(by: -2) == [9, 7, 5, 3, 1]
(0 ..< 9).striding(by: -2) ==    [7, 5, 3, 1]
(0 <.. 9).striding(by: -2) == [9, 7, 5, 3, 1]
(0 <.< 9).striding(by: -2) ==    [7, 5, 3, 1]

(0 ... 9).striding(by: -3) == [9, 6, 3, 0]
(0 ..< 9).striding(by: -3) ==    [6, 3, 0]
(0 <.. 9).striding(by: -3) == [9, 6, 3]
(0 <.< 9).striding(by: -3) ==    [6, 3]
To reverse a stride, call reverse() on the results:

(0 ... 9).striding(by: 2).reverse() == [8, 6, 4, 2, 0]
We note that striding by 0 should be always be a precondition failure.

 
<https://gist.github.com/erica/a51a981ee0352235204692affa959307#alternatives-considered>Alternatives
 Considered

During the on-list discussion, we considered various scenarios that took 
closed/inclusive bounds into account or excluded open bounds for starting 
values. For example, we might have prohibited scenarios where multiple 
interpretations of an intended behavior might exist: is (0 ..< 9).striding(by: 
-2) a precondition failure? We settled on the simplest, most straight-forward 
implementation involving the fewest compiler warnings and the lowest likelihood 
of precondition failures. We subscribe to the "Dave Abrahams Philosophy": 
excessive special casing and warning scenarios more likely indicates bad 
language design than bad user comprehension.

 
<https://gist.github.com/erica/a51a981ee0352235204692affa959307#future-directions>Future
 Directions

We intend to follow up with an expanded operator vocabulary that includes fully 
open ranges (<.<), fully closed ranges (...) and both half open ranges (<.., 
..<). These will support the full vocabulary laid out in the Detail Design 
section.

Upon adoption, the Swift community may consider expanding this approach to 
collection indices, for example:

let a = [8, 6, 7, 5, 3, 0, 9]
for e in a.striding(by: 3) {
    print(e) // 8, then 5, then 9
}
Striding offers a fundamental operation over collections. The consistent 
approach introduced in this proposal 
<http://article.gmane.org/gmane.comp.lang.swift.evolution/13936> helps support 
the extension of stride semantics to collections.

 
<https://gist.github.com/erica/a51a981ee0352235204692affa959307#acknowlegements>Acknowlegements

Thanks, Dave Abrahams, Matthew Judge

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to