[swift-evolution] [pitch] Comparison Reform

Dave Abrahams dabrahams at apple.com
Sat Apr 22 15:47:23 CDT 2017


on Tue Apr 18 2017, Ben Cohen <ben_cohen-AT-apple.com> wrote:

>> On Apr 17, 2017, at 9:40 PM, Chris Lattner via swift-evolution <swift-evolution at swift.org> wrote:
>> 
>> 
>>> On Apr 17, 2017, at 9:07 AM, Joe Groff via swift-evolution <swift-evolution at swift.org> wrote:
>>> 
>
>>> 
>>>> On Apr 15, 2017, at 9:49 PM, Xiaodi Wu via swift-evolution <swift-evolution at swift.org> wrote:
>>>> 
>>>> For example, I expect `XCTAssertEqual<T : FloatingPoint>(_:_:)` to
>>>> be vended as part of XCTest, in order to make sure that
>>>> `XCTAssertEqual(resultOfComputation, Double.nan)` always fails.
>>> 
>>> Unit tests strike me as an example of where you really *don't* want
>>> level 1 comparison semantics. If I'm testing the output of an FP
>>> operation, I want to be able to test that it produces nan when I
>>> expect it to, or that it produces the right zero.
>> 
>> I find it very concerning that == will have different results based
>> on concrete vs generic type parameters.  This can only lead to
>> significant confusion down the road.  I’m highly concerned about
>> situations where taking a concrete algorithm and generalizing it
>> (with generics) will change its behavior.
>> 
>
> It is already the case that you can start with a concrete algorithm,
> generalize it, and get confusing results – just with a different
> starting point. If you start with a concrete algorithm on Int, then
> generalize it to all Equatable types, then your algorithm will have
> unexpected behavior for floats, because these standard library types
> fail to follow the rules explicitly laid out for conforming to
> Equatable.
>
> This is bad. Developers need to be able to rely on those rules. The standard library certainly does:
>
> let a: [Double] = [(0/0)]
> var b = a
>
> // true, because fast path buffer pointer comparison:
> a == b
>
> b.reserveCapacity(10) // force a reallocation
>
> // now false, because memberwise comparison and nan != nan,
> // violating the reflexivity requirement of Equatable:
> a == b 
>
> Maybe we could go through and special-case all the places in the
> standard library that rely on this, accounting for the floating point
> behavior (possibly reducing performance as a result). But we shouldn't
> expect users to.
>
> This is a bump in the rug – push it down in one place, it pops up in
> another. I feel like this proposal at least moves the bump to where
> fewer people will trip over it. I think it highly likely that the
> intersection of developers who understand enough about floating point
> to write truly correct concrete code, but won’t know about or discover
> the documented difference in generic code, is far smaller than the set
> of people who hit problems with the existing behavior.
>
>  A more comprehensive solution, with additional protocols or
> overloads, representation of unordered comparison etc, might be able
> to flatten the rug completely, but probably at the cost of introducing
> complexity that could act as a barrier to entry into the world of
> writing generic code.

I hadn't had time to read this before, but now my inbox is getting too
big and I am forced to deal with the backlog.  Just wanted to say, this
is a great response, Ben.  Bravo!

-- 
-Dave


More information about the swift-evolution mailing list