[swift-evolution] [swift-evolution-announce] [Returned for revision] SE-0050: Decoupling Floating Point Strides from Generic Implementations

Dave Abrahams dabrahams at apple.com
Tue May 31 12:16:09 CDT 2016

on Mon May 30 2016, Brent Royal-Gordon <swift-evolution at swift.org> wrote:

>> The core team believes that the existing strideable API cannot efficiently and correctly handle all the real-world use cases one would want.  However, a multiplication-based implementation similar to the one proposed in SE-0050 (but potentially extended) seems sufficiently general to solve the existing use cases as well as solve the floating point error accumulation issue.  Once the design of this iterates on swift-evolution, it would be great to see a revised version of this proposal.
> Can you give any indication of what's wrong with the proposed API?

For example, a multiplication-based implementation like the one proposed
for floating point could be made to work for all the current models of
Strideable in the standard library, but it would not generalize
efficiently to handling arbitrary-precision integers or complex numbers
or even to efficiently striding over Float.  We believe such a protocol
should be designed, and we fundamentally disagree with the proposal's
claim that abstracting over integers and floating point is wrong.

Until we have the right API design for Strideable, we believe the
accumulating problem can be fixed without changing Strideable's public
API, e.g. by adding underscored protocol requirements for which we can
provide specialized implementations using protocol extensions
constrained to Stride : FloatingPointType.  We look forward to accepting
a pull request to make this change, which doesn't require an evolution
proposal, and we expect that change to usefully inform the question of
how to change Strideable.

> Personally, what bothered me about it is that it seems too float-specific. The way I would design it is to add multiplication to Strideable:
> 	public protocol Strideable: Comparable {
> 		typealias Stride: SignedNumber
> 		func distance(to other: Self) -> Stride
> 		func advanced(by stride: Stride) -> Self
> 		static func scale(_ stride: Stride, by multiplier: Stride) -> Stride
> 	}
> And then have a refined protocol for types like Int which are safe to repeatedly advance:
> 	/// An AccumulatingStrideable is a Strideable which guarantees that:
> 	///
> 	///	(0..<10).reduce(value) { val, _ in val.advanced(by: stride) } == value.advanced(by: T.scale(stride, by: 10))
> 	/// 
> 	/// In other words, the result of repeatedly advancing any value by any stride *n* times is exactly equal to the 
> 	/// result of advancing it once by that stride scaled up *n* times.
> 	public protocol AccumulatingStrideable: Strideable {}
> Then you have two forms of `stride(from:to:by:)`:
> 	public func stride<T: Strideable>(from start: T, to end: T, by stride: T.Stride) -> StrideTo<T>
> 	public func stride<T: AccumulatingStrideable>(from start: T, to end: T, by stride: T.Stride) -> AccumulatingStrideTo<T>
> Obviously there are many designs we could consider along these lines, and I don't want to get bogged down in the details of choosing one at this point. What I'm asking is, is this the general *kind* of design you're looking for compared to SE-0050, one which is not specific to FloatingPoint types? Or are you looking for a redesign which addresses different issues from these?


More information about the swift-evolution mailing list