[swift-evolution] [Draft][Proposal] Formalized Ordering
Xiaodi Wu
xiaodi.wu at gmail.com
Fri Jul 22 22:08:13 CDT 2016
On Fri, Jul 22, 2016 at 9:57 PM, Dave Abrahams <dabrahams at apple.com> wrote:
>
> on Fri Jul 22 2016, Xiaodi Wu <xiaodi.wu-AT-gmail.com> wrote:
>
> > On Fri, Jul 22, 2016 at 9:46 PM, Dave Abrahams <dabrahams at apple.com>
> wrote:
> >
> >>
> >> on Fri Jul 22 2016, Xiaodi Wu <xiaodi.wu-AT-gmail.com> wrote:
> >>
> >> > On Fri, Jul 22, 2016 at 9:23 PM, Matthew Johnson <
> matthew at anandabits.com
> >> >
> >> > wrote:
> >> >
> >> >>
> >> >> On Jul 22, 2016, at 9:17 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
> >> >>
> >> >> On Fri, Jul 22, 2016 at 9:15 PM, Matthew Johnson via swift-evolution
> <
> >> >> swift-evolution at swift.org> wrote:
> >> >>
> >> >>>
> >> >>> On Jul 22, 2016, at 9:04 PM, Dave Abrahams via swift-evolution <
> >> >>> swift-evolution at swift.org> wrote:
> >> >>>
> >> >>>
> >> >>> on Fri Jul 22 2016, Matthew Johnson <swift-evolution at swift.org>
> wrote:
> >> >>>
> >> >>> On Jul 22, 2016, at 8:37 PM, Xiaodi Wu via swift-evolution
> >> >>> <swift-evolution at swift.org> wrote:
> >> >>>
> >> >>> On Fri, Jul 22, 2016 at 8:20 PM, Dave Abrahams via swift-evolution
> >> >>> <swift-evolution at swift.org
> >> >>>
> >> >>>
> >> >>> <mailto:swift-evolution at swift.org <swift-evolution at swift.org>>>
> >> >>> wrote:
> >> >>>
> >> >>> on Fri Jul 22 2016, Daniel Duan <daniel-AT-duan.org
> >> >>> <http://daniel-at-duan.org/>> wrote:
> >> >>>
> >> >>> On Jul 22, 2016, at 3:00 PM, Dave Abrahams via swift-evolution
> >> >>> <swift-evolution at swift.org
> >> >>> <mailto:swift-evolution at swift.org <swift-evolution at swift.org>>>
> >> >>> wrote:
> >> >>>
> >> >>>
> >> >>> on Fri Jul 22 2016, Daniel Duan
> >> >>> <swift-evolution at swift.org
> >> >>> <mailto:swift-evolution at swift.org <swift-evolution at swift.org>>
> >> >>> <mailto:swift-evolution at swift.org <swift-evolution at swift.org>
> >> >>> <mailto:swift-evolution at swift.org <swift-evolution at swift.org>>>>
> >> >>> wrote:
> >> >>>
> >> >>>
> >> >>> On Jul 22, 2016, at 11:05 AM, Dave Abrahams via swift-evolution
> >> >>> <swift-evolution at swift.org
> >> >>> <mailto:swift-evolution at swift.org <swift-evolution at swift.org>>
> >> >>> <mailto:swift-evolution at swift.org <swift-evolution at swift.org>
> >> >>> <mailto:swift-evolution at swift.org <swift-evolution at swift.org>>>>
> >> >>> wrote:
> >> >>>
> >> >>>
> >> >>> on Thu Jul 21 2016, Duan
> >> >>>
> >> >>>
> >> >>> <swift-evolution at swift.org
> >> >>> <mailto:swift-evolution at swift.org <swift-evolution at swift.org>>
> >> >>> <mailto:swift-evolution at swift.org <swift-evolution at swift.org>
> >> >>> <mailto:swift-evolution at swift.org <swift-evolution at swift.org>>>
> >> >>> <mailto:swift-evolution at swift.org <swift-evolution at swift.org>
> >> >>> <mailto:swift-evolution at swift.org <swift-evolution at swift.org>>
> >> >>> <mailto:swift-evolution at swift.org <swift-evolution at swift.org>
> >> >>> <mailto:swift-evolution at swift.org <swift-evolution at swift.org>>>>>
> >> >>> wrote:
> >> >>>
> >> >>> Great proposal. I want to second that areSame may mislead user to
> >> >>> think this is about identity.
> >> >>>
> >> >>> I like areEquivalent() but there may be better names.
> >> >>>
> >> >>>
> >> >>> It really *is* about identity as I posted in a previous message.
> But
> >> >>> that doesn't change the fact that areEquivalent might be a better
> name.
> >> >>> It's one of the things we considered; it just seemed long for no
> real
> >> >>> benefit.
> >> >>>
> >> >>>
> >> >>> If the addresses of the arguments aren’t being used, then we don’t
> >> >>> consider
> >> >>> them part of their *identity*. I can follow this logic. My fear is
> most
> >> >>> users
> >> >>> won’t make this leap on their own and get the same initial
> impression
> >> as
> >> >>> I did.
> >> >>> It's entirely possible this fear is unfounded. Some educated
> >> bikesheding
> >> >>> wouldn't hurt here IMO :)
> >> >>>
> >> >>>
> >> >>> Well, it's still a very real question whether we ought to have the
> >> >>> additional API surface implied by areSame, or wether we should
> collapse
> >> >>> it with ===.
> >> >>>
> >> >>>
> >> >>> To spell this out (because I had to think about it for a second):
> ===
> >> >>> will be derived from
> >> >>> <=>,
> >> >>> but also becomes default implementation for ==, which remains open
> for
> >> >>> customization.
> >> >>>
> >> >>>
> >> >>> I was imagining roughly this (untested):
> >> >>>
> >> >>> /// Two references are identical if they refer to the same
> >> >>> /// instance.
> >> >>> ///
> >> >>> /// - Note: Classes with a more-refined notion of “identical”
> >> >>> /// should conform to `Identifiable` and implement `===`.
> >> >>> func ===(lhs: AnyObject, rhs: AnyObject) -> Bool {
> >> >>> ObjectIdentifier(lhs) == ObjectIdentifier(rhs)
> >> >>> }
> >> >>>
> >> >>> /// Supports testing that two values of `Self` are identical
> >> >>> ///
> >> >>> /// If `a` and `b` are of type `Self`, `a === b` means that
> >> >>> /// `a` and `b` are interchangeable in most code. A conforming
> >> >>> /// type can document that specific observable characteristics
> >> >>> /// (such as the `capacity` of an `Array`) are inessential and
> >> >>> /// thus not to be considered as part of the interchangeability
> >> >>> /// guarantee.
> >> >>> ///
> >> >>> /// - Requires: `===` induces an equivalence relation over
> >> >>> /// instances.
> >> >>> /// - Note: conforming types will gain an `==` operator that
> >> >>> /// forwards to `===`.
> >> >>> /// - Note: Types that require domain-specific `==`
> >> >>> /// implementations with different semantics (e.g. floating
> >> >>> /// point) should define a more-specific overload of `==`,
> >> >>> /// which will be used in contexts where the static type is
> >> >>> /// known to the compiler.
> >> >>> /// - Note: Generic code should usually use `==` to compare
> >> >>> /// conforming instances; that will always dispatch to `===`
> >> >>> /// and will be unaffected by more specific overloads of
> >> >>> /// `==`.
> >> >>> protocol Identifiable { // née Equatable name is negotiable
> >> >>> func ===(_: Self, _: aSelf) -> Bool
> >> >>> }
> >> >>>
> >> >>> /// Default definition of `==` for Identifiable types.
> >> >>> func ==<T: Identifiable>(lhs: T, rhs: T) -> Bool {
> >> >>> return lhs === rhs
> >> >>> }
> >> >>>
> >> >>> /// Conforming types have a default total ordering.
> >> >>> ///
> >> >>> /// If `a` and `b` are of type `Self`, `a <=> b` means that
> >> >>> /// `a` and `b` are interchangeable in most code. A conforming
> >> >>> /// type can document that specific observable characteristics
> >> >>> /// (such as the `capacity` of an `Array`) are inessential and
> >> >>> /// thus not to be considered as part of the interchangeability
> >> >>> /// guarantee.
> >> >>> ///
> >> >>> /// - Requires: `<=>` induces a total ordering over
> >> >>> /// instances.
> >> >>> /// - Requires: the semantics of `<=>` are consistent with
> >> >>> /// those of `===`. That is, `(a <=> b) == .equivalent`
> >> >>> /// iff `a === b`.
> >> >>>
> >> >>> For floating point, I'd hope that `a === b` if `(a <=> b) == .same`
> >> *but
> >> >>> not iff*. This is to satisfy IEEE 754: "Comparisons shall ignore the
> >> sign
> >> >>> of zero (so +0 = −0)”.
> >> >>>
> >> >>>
> >> >>> The point of this design is that `===` means identity and that
> `.same `
> >> >>> also means identity.
> >> >>>
> >> >>> Since this is new territory I suppose we get to decide what identity
> >> >>> means for floating point. Should +0 and -0 have the same identity
> or
> >> >>> not? I’ll leave the answer to folks more knowledgable about
> numerics
> >> >>> than I.
> >> >>>
> >> >>>
> >> >>> It's settled law
> >> >>>
> >>
> https://en.wikipedia.org/wiki/IEEE_floating_point#Total-ordering_predicate
> >> >>> :-)
> >> >>>
> >> >>>
> >> >>> Yes, assuming we want to define identity in terms of the IEEE
> >> definition
> >> >>> of total ordering.
> >> >>>
> >> >>
> >> >> I see what you're saying here. That could work. Comparable `===` and
> >> >> Equatable `<=>` could do its own thing, and FloatingPoint
> >> >> `isTotallyOrdered(below:)` can preserve the IEEE definition of total
> >> >> ordering
> >> >>
> >> >>
> >> >> Actually, I was hinting at your argument that `===` true iff `<=>`
> same
> >> >> shouldn’t be a semantic requirement of the protocols.
> >> >>
> >> >> This is another option, but I don’t think it’s going to fly. It
> seems
> >> >> reasonable to assume that `<=>` will have IEEE semantics. We will
> trip
> >> a
> >> >> lot of people up if it doesn’t. That’s a big reason we can’t
> consider
> >> >> changing floating point `==` to define an equivalence relation.
> >> >>
> >> >
> >> > Actually, here I doubt it. The total ordering isn't exposed as part of
> >> any
> >> > comparison operator defined in the IEEE spec. In fact, the total
> ordering
> >> > wasn't introduced until a (fairly) recent IEEE revision, IIUC.
> Breaking
> >> > `==` would definitely cause people to jump, but `<=>` needn't be the
> IEEE
> >> > totalOrder predicate IMO.
> >>
> >> Wait, I thought we were saying that `<=>` could be IEEE totalOrder, and
> >> `===` could be like `==` but with well-behaved NaNs, so it's still an
> >> equivalence relation, thus declaring the signedness of 0 to be
> >> inessential.
> >>
> >
> > I was (that was the "=== if but not iff <=>" business above), then I
> > thought Matthew was saying something different and agreed with him.
> >
> > What I thought that Matthew thought was actually very insightful. He
> didn't
> > actually think this, apparently, but: IEEE totalOrder does exactly what
> it
> > says on the tin. But, it is not useful for any generic comparisons or (as
> > far as I'm aware) any generic sorting algorithms. I cannot conceive of a
> > numeric algorithm or a generic algorithm that relies on two equal
> floating
> > point values being ordered based on their binary representation. We
> should
> > have some way of exposing totalOrder to a user of a BinaryFloatingPoint
> > type, but I don't know that it should be the basis for floating point
> > *identity* with respect to protocol conformance. It's explicitly *not*
> what
> > IEEE recommends for comparison anyway.
>
> That makes sense. Perhaps IEEE hasn't actually made a principled
> decision about which aspects of floating point numbers are essential,
> and we have to do it for them.
>
I may have to walk back some comments. IEEE totalOrder rules should work
fine for <=> if we relax "a === b iff (a <=> b) == .same", as it explicitly
states:
a) If x < y, totalOrder(x, y) is true. [i.e. compares ascending]
b) If x > y, totalOrder(x, y) is false. [i.e. does not compare ascending]
This is where Steve's expertise comes in. In either case, I think we might
have a solution for `===` behaving weirdly in generic algorithms.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160722/e174a93d/attachment.html>
More information about the swift-evolution
mailing list