[swift-dev] Rationalizing FloatingPoint conformance to Equatable

Xiaodi Wu xiaodi.wu at gmail.com
Thu Oct 26 10:19:07 CDT 2017


On Thu, Oct 26, 2017 at 07:52 Jonathan Hull <jhull at gbis.com> wrote:

> On Oct 25, 2017, at 11:22 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>
> On Wed, Oct 25, 2017 at 11:46 PM, Jonathan Hull <jhull at gbis.com> wrote:
>
>> As someone mentioned earlier, we are trying to square a circle here. We
>> can’t have everything at once… we will have to prioritize.  I feel like the
>> precedent in Swift is to prioritize safety/correctness with an option
>> ignore safety and regain speed.
>>
>> I think the 3 point solution I proposed is a good compromise that follows
>> that precedent.  It does mean that there is, by default, a small
>> performance hit for floats in generic contexts, but in exchange for that,
>> we get increased correctness and safety.  This is the exact same tradeoff
>> that Swift makes for optionals!  Any speed lost can be regained by
>> providing a specific override for FloatingPoint that uses ‘&==‘.
>>
>
> My point is not about performance. My point is that `Numeric.==` must
> continue to have IEEE floating-point semantics for floating-point types and
> integer semantics for integer types, or else existing uses of `Numeric.==`
> will break without any way to fix them. The whole point of *having*
> `Numeric` is to permit such generic algorithms to be written. But since
> `Numeric.==` *is* `Equatable.==`, we have a large constraint on how the
> semantics of `==` can be changed.
>
>
> It would also conform to the new protocol and have it’s Equatable
> conformance depreciated. Once we have conditional conformances, we can add
> Equatable back conditionally.  Also, while we are waiting for that, Numeric
> can provide overrides of important methods when the conforming type is
> Equatable or FloatingPoint.
>
>
> For example, if someone wants to write a generic function that works both
>> on Integer and FloatingPoint, then they would have to use the new protocol
>> which would force them to correctly handle cases involving NaN.
>>
>
> What "new protocol" are you referring to, and what do you mean about
> "correctly handling cases involving NaN"? The existing API of `Numeric`
> makes it possible to write generic algorithms that accommodate both integer
> and floating-point types--yes, even if the value is NaN. If you change the
> definition of `==` or `<`, currently correct generic algorithms that use
> `Numeric` will start to _incorrectly_ handle NaN.
>
>
>
> #1 from my previous email (shown again here):
>
> Currently, I think we should do 3 things:
>>>
>>> 1) Create a new protocol with a partial equivalence relation with
>>> signature of (T, T)->Bool? and automatically conform Equatable things to it
>>> 2) Depreciate Float, etc’s… Equatable conformance with a warning that it
>>> will eventually be removed (and conform Float, etc… to the partial
>>> equivalence protocol)
>>> 3) Provide an '&==‘ relation on Float, etc… (without a protocol) with
>>> the native Float IEEE comparison
>>
>>
> In this case, #2 would also apply to Numeric.  You can think of the new
> protocol as a failable version of Equatable, so in any case where it can’t
> meet equatable’s rules, it returns nil.
>

Again, Numeric makes possible the generic use of == with floating-point
semantics for floating-point values and integer semantics for integer
values; this design would not.

If speed is super important in that particular case, then they can write
>> overrides for the FloatingPoint case which uses &==, and for Equatable
>> which uses ==.
>>
>> Because Float’s Equatable conformance is just being depreciated (with a
>> warning/fixit), authors have at least a version to decide whether speed or
>> correctness (or hopefully both) is most important to them.
>>
>
> My point here is not about generic algorithms written to take any
> Equatable value; it's about protocol-based numeric algorithms, which we in
> SE-0104 devoted much time and energy to support in the first place.
>
>
> See above.
>
> Thanks,
> Jon
>
>
>
>> Thanks,
>> Jon
>>
>> P.S. We really should not be comparing against the speed of algorithms
>> which don’t correctly handle NaN. Let’s compare Apples to Apples.
>>
>
> Again, what do you mean about "correctly handle NaN"? Most algorithms
> today *do* correctly handle NaN, in that they are concordant with the
> IEEE-specified behavior. Set *not* deduplicating NaN *is* correct handling
> of NaN, for instance, for as long as NaN != NaN.
>
> On Oct 25, 2017, at 6:36 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>>
>> On Wed, Oct 25, 2017 at 8:26 PM, Jonathan Hull <jhull at gbis.com> wrote:
>>
>>> > On Oct 25, 2017, at 9:01 AM, David Sweeris via swift-dev <
>>> swift-dev at swift.org> wrote:
>>> >
>>> > That said, I fully acknowledge that this is all above my pay grade
>>> (also I hadn't realized that the issue was as settled as it apparently is).
>>> If splitting the protocols is a no-go from the get go, I'll go back to
>>> trying to figure out a better way to handle it without doing that.
>>>
>>>
>>> I don’t think it is settled.  The issue that Xiaodi mentioned was a
>>> PartiallyEq protocol which still had a signature of (T,T)->Bool.  People
>>> just used that protocol instead of Equatable without taking into account
>>> the difference in behavior.  The signature of (T,T)->Bool? changes things
>>> because people are forced to deal with the optional.
>>>
>>> Currently, I think we should do 3 things:
>>>
>>> 1) Create a new protocol with a partial equivalence relation with
>>> signature of (T, T)->Bool? and automatically conform Equatable things to it
>>> 2) Depreciate Float, etc’s… Equatable conformance with a warning that it
>>> will eventually be removed (and conform Float, etc… to the partial
>>> equivalence protocol)
>>> 3) Provide an '&==‘ relation on Float, etc… (without a protocol) with
>>> the native Float IEEE comparison
>>>
>>> I think this provides several benefits.  #3 allows pure speed when
>>> needed, but not in a generic context (and is appropriately scary to cause
>>> some thought).  #1 forces correct handling in generic contexts.  #2 gives
>>> people time to make the adjustment, but also eventually requires them to
>>> switch to using #1 or #3.
>>>
>>> I think it will cause A LOT of currently incorrect code to be fixed.
>>>
>>
>> One issue which occurred to me only recently, which I hadn't considered,
>> renders my `&==` idea and all similar schemes untenable:
>>
>> Useful algorithms can and are written which operate on both
>> floating-point and integer numeric types. In fact, the whole point of
>> laboriously designing `Numeric` as part of SE-0104 was to make it possible
>> to do so. If IEEE comparison is relegated to `FloatingPoint` and the only
>> operator remaining on `Numeric` is `==`, then not only will there be a
>> mandatory performance hit, but currently correct algorithms can be broken
>> with absolutely no way to express a fix.
>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-dev/attachments/20171026/11b18fa0/attachment.html>


More information about the swift-dev mailing list