On Sat, Apr 22, 2017 at 7:02 PM, Matthew Johnson <[email protected]> wrote:
> > > Sent from my iPad > > On Apr 22, 2017, at 4:53 PM, Xiaodi Wu via swift-evolution < > [email protected]> wrote: > > On Sat, Apr 22, 2017 at 4:14 PM, Dave Abrahams <[email protected]> > wrote: > >> >> on Tue Apr 18 2017, Xiaodi Wu <xiaodi.wu-AT-gmail.com> wrote: >> >> > On Tue, Apr 18, 2017 at 10:40 AM, Ben Cohen via swift-evolution < >> > [email protected]> wrote: >> > >> >> >> >> On Apr 17, 2017, at 9:40 PM, Chris Lattner via swift-evolution < >> >> [email protected]> wrote: >> >> >> >> >> >> On Apr 17, 2017, at 9:07 AM, Joe Groff via swift-evolution < >> >> [email protected]> wrote: >> >> >> >> >> >> On Apr 15, 2017, at 9:49 PM, Xiaodi Wu via swift-evolution < >> >> [email protected]> 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. >> >> >> > >> > I was not thinking about the issue illustrated above, but this is >> > definitely problematic to me. >> > >> > To be clear, this proposal promises that `[0 / 0 as Double]` will be >> made >> > to compare unequal with itself, yes? >> >> Nope. >> >> As you know, equality of arrays is implemented generically and based on >> the equatable conformance of their elements. Therefore, two arrays of >> equatable elements are equal iff the conforming implementation of >> Equatable's == is true for all elements. >> >> > It is very clear that here we are working with a concrete FP type and >> > not in a generic context, and thus all IEEE FP behavior should apply. >> >> I suppose that's one interpretation, but it's not the right one. >> >> If this were C++, it would be different, because of the way template >> instantiation works: in a generic context like the == of Array, the >> compiler would look up the syntactically-available == for the elements >> and use that. But Swift is not like that; static lookup is done at the >> point where Array's == is compiled, and it only finds the == that's >> supplied by the Element's Equatable conformance. >> >> This may sound like an argument based on implementation details of the >> language, and to some extent it is. But that is also the fundamental >> nature of the Swift language (and one for which we get many benefits), >> and it is hopeless to paper over it. For example, I can claim that all >> doubles are equal to one another: >> >> 9> func == (lhs: Double, rhs: Double) -> Bool { return true } >> 10> 4.0 == 1.0 >> $R2: Bool = true >> 11> [4.0] == [1.0] // so the arrays should be equal too! >> $R3: Bool = false >> >> Another way to look at this is that Array is not a numeric vector, and >> won't be one no matter what you do ([1.0] + [2.0] => [1.0, 2.0]). So it >> would be wrong for you to expect it to reflect the numeric properties of >> its elements. >> > > I understand that's how the generic Array<T> would work, but the proposal > as written promises FP-aware versions of these functions. That is to say, I > would expect the standard library to supply an alternative implementation > of equality for Array<T where T : FloatingPoint>. > > > Are you suggesting it implies that Array's Equatable conformance is > implemented differently when T: FloatingPoint? Is it even possible to > provide such an implementation given the current restriction that bans > overlapping conformance? (If there is a technique for implementing > something like this in Swift 4 I would love to learn it) > I don't believe it's possible, but there is compiler magic being proposed to make this protocol stick together, so we are not bound by the limits of Swift 4-expressible designs.
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
