> On Dec 19, 2015, at 1:47 PM, Brent Royal-Gordon <br...@architechies.com> > wrote: > >>> for lat in (CGFloat(-60)...60).by(30) { >>> print(lat) >>> } >>> >>> for lat in (CGFloat(-60)..<60).by(30) { >>> print(lat) >>> } >> >> This is nice; why don't we put it in the standard library and get rid of the >> "stride" methods? > > One practical reason is that interval.start must always be before > interval.end, so this makes striding in reverse difficult.
We could declare that negative strides cause us to start at the end rather than at the start. > Another is that the precedence of the interval operators forces additional > parentheses, so the resulting code is usually ugly. I'm aware of that, but it seems less ugly to me than the alternative, and more importantly it keeps the range/interval EDSL more integrated. > (And making them higher-precedence than member access has its own problems, > like `0..<(foo.count)`.) > > Honestly, as much as we try to avoid them, I think the old free functions in > Swift 1 gave us the best-looking code. Adapted to use intervals: > > for lat in stride(CGFloat(-60)…60, by: 30) { > print(lat) > } > > Or, a little more cleanly: > > for lat: CGFloat in stride(-60…60, by: 30) { > print(lat) > } > If you don’t like the function syntax, one funky alternative might be to > overload `+`: > > for lat: CGFloat in -60...60 + 30 { // Meaning “increment by 30 > each time" > print(lat) > } > > Hmm. Rather than overloading, maybe we can use two recently-freed-up > operators which are traditionally associated with looping... > > infix operator ++ { associativity none precedence 130 } // 130 is > looser than the interval operators > infix operator -- { associativity none precedence 130 } > > func ++ <Bound: Strideable>(interval: ClosedInterval<Bound>, stride: > Bound.Stride) -> StrideThrough<Bound> { > // These implementations are just how they work against the current > public API, of course. > return interval.start.stride(through: interval.end, by: stride) > } > > func ++ <Bound: Strideable>(interval: HalfOpenInterval<Bound>, stride: > Bound.Stride) -> StrideTo<Bound> { > return interval.start.stride(to: interval.end, by: stride) > } > > func -- <Bound: Strideable>(interval: ClosedInterval<Bound>, stride: > Bound.Stride) -> StrideThrough<Bound> { > return interval.end.stride(through: interval.start, by: -stride) > } > > func -- <Bound: Strideable>(interval: HalfOpenInterval<Bound>, stride: > Bound.Stride) -> StrideTo<Bound> { > return interval.end.stride(to: interval.start, by: -stride) > } > > Giving you: > > // Counts up from start by 30 > for lat: CGFloat in -60...60 ++ 30 { > print(lat) > } > > // Counts down from end by 30 > for lat: CGFloat in -60...60 -- 30 { > print(lat) > } > > Perhaps this could even be extended to take a Bound -> Bound function as the > right-hand parameter, allowing for the sort of arbitrary incrementing that > some complain we've lost without C-style for: > > for lat: CGFloat in 1...60 ++ { $0 * 2 } { > print(lat) > } > > And, of course, we could also provide unary variants which do +1 and -1: > > // Counts up from start by 1 > for lat: CGFloat in -60...60++ { > print(lat) > } > > // Counts down from end by 1 > for lat: CGFloat in -60...60-- { > print(lat) > } None of those syntaxes fly for me, I'm afraid. They all look like line noise (and some have precedence problems); I much prefer requiring a set of parentheses. -Dave _______________________________________________ swift-dev mailing list swift-dev@swift.org https://lists.swift.org/mailman/listinfo/swift-dev