on Thu Apr 07 2016, Brent Royal-Gordon <brent-AT-architechies.com> wrote:

>>> calendar.using(.Day).stride(from: startDate, to: endDate, by: 1)
>> 
>>> The `start` and `end` parameters could be grouped together into a
>>> single parameter to match `stride(over:by:)`, but you can't put the
>>> calendar or the unit into the stride—without them, there is no
>
>>> coherent way to calculate the distance between two dates.
>>> 
>>> So if some types need a strider, and will need to have the method
>>> structured as `strider.stride(something:by:)`, it seems like the
> free
>>> function version for types which *don't* need a strider ought to be
>>> `stride(something:by:)`. The `something.striding(by:)` design can't
> be
>>> easily adapted to this situation.
>> 
>>  calendar[startDate..<endDate].striding(by: .Day)
>> 
>> ?
>
> Actually, it would need to be something like
> `calendar[startDate..<endDate, unit: .Day].striding(by: 1)`, because
> NSCalendarUnit is not itself a stride, it is the *unit* of the
> stride. 

Maybe:

  calendar.days[startDate..<endDate].striding(by: 1)

> But even that doesn't quite help.
>
> Here's the issue.
>
> Take a look at today's Strideable. Stripped of comments and irrelevant
> annotations, you have:
>
>       protocol Strideable : Comparable {
>           associatedtype Stride : SignedNumberType
>           func distanceTo(other: Self) -> Stride
>           func advancedBy(n: Stride) -> Self
>       }
>
> The problem is that there's no good way to get the calendar and unit
> into these methods. If you package them inside `Stride`, then
> `distanceTo` has no idea what calendar or unit it's supposed to
> return. If you package them inside `Self`, then `distanceTo` has two
> calendars and two units, and they might not agree (and the type system
> can't catch this issue).
>
> To fix this, you need to have a single instance which performs the
> calculation. For simple Strideable types, this instance would not do
> very much, but for dates, it would factor in the calendar and unit.

I follow all the above; it's a good explanation of the problem.
However, it doesn't explain why

  calendar[startDate..<endDate, unit: .Day].striding(by: 1)

“doesn't quite help.”  It seems to me that 

  calendar[startDate..<endDate, unit: .Day]

does factor in the calendar and unit.

> For example, suppose you modify `Strideable` so that, instead of
> applying to the values participating in the striding, it applies to
> the instance containing those values:
>
>       public protocol Strideable {
>               associatedtype Element: Comparable
>               associatedtype Stride: SignedNumber
>
>               var start: Value
>               var end: Value
>
>               public func distance(from earlier: Element, to later: Element) 
> -> Stride
>               public func advance(element: Element, by stride: Stride) -> 
> Element
>       }

Presumably you mean for Strideable to have a striding(by:_) method as well?

If so, how is this fundamentally different from Collection?  Shouldn't
every Collection support this?

> Now, with some *really* aggressive conditional conformance work, you
> could do this:
>
>       extension Range: Strideable where Element == Int {
>               typealias Stride = Int
>
>               public func distance(from earlier: Int, to later: Int)
> -> Int {
>                       return later - earlier
>               }
>               public func advance(element: Int, by stride: Int) {
>                       return value + stride
>               }
>       }
>       extension Range: Strideable where Element == Double {
>               // Ignoring the accumulation issue.
>               typealias Stride = Double
>
>               public func distance(from earlier: Int, to later: Int) -> Int {
>                       return later - earlier
>               }
>               public func advance(element: Double, by stride: Double) {
>                       return element + stride
>               }
>       }

Except we don't have that capability today.  Instead we'd be using
overloads of ..< and ... to produce more-capable range types, c.f.  
https://github.com/apple/swift/blob/swift-3-indexing-model/stdlib/public/core/Range.swift#L504
https://github.com/apple/swift/blob/swift-3-indexing-model/stdlib/public/core/Range.swift#L519

>       
>       // etc., for each type you care about.
>       // 
>       // This could be automated by creating a `RangeStrideable` protocol 
> similar to the old Strideable,
>       // and having types with this automatic behavior conform to it. You 
> could then have a single:
>       // extension Range: Strideable where Element: RangeStrideable
>
> It would not be possible to stride directly over a range of NSDates,
> but you could have a "calendar range" which could be `Strideable`,
> like so:
>
>       struct NSCalendarRange {
>               var start: NSDate
>               var end: NSDate
>
>               var calendar: NSCalendar
>               var unit: NSCalendarUnit
>
>               var options: NSCalendarOptions
>               // This mainly contains rounding options. Interestingly, NSDate 
> is like Double in that
>               // it accumulates errors through repeated addition. To fix 
> that, I have discovered
>               // a truly marvelous design which this email is too small to 
> contain.
>       }
>       extension NSCalendarRange: Strideable {
>               typealias Value = NSDate
>               typealias Stride = Int
>
>               public func distance(from earlier: NSDate, to later: NSDate) -> 
> Int {
>                       let components = calendar.components(unit, from: 
> earlier, to: later, options: options)
>                       return components.value(forComponent: unit)
>               }
>               public func advance(value: NSDate, by stride: Int) -> NSDate {
>                       return calendar.date(byAdding: unit, value: distance, 
> to: value, options: options)!
>               }
>       }
>
> So I guess `striding(by:)` can be adapted to date arithmetic, but only
> if we adjust our conception of what a stride is striding over.


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

Reply via email to