[swift-dev] Rationalizing FloatingPoint conformance to Equatable

David Sweeris davesweeris at mac.com
Thu Oct 26 12:40:05 CDT 2017


> On Oct 26, 2017, at 9:40 AM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
> 
> On Thu, Oct 26, 2017 at 11:38 AM, Jonathan Hull <jhull at gbis.com <mailto:jhull at gbis.com>> wrote:
> 
>> On Oct 26, 2017, at 9:34 AM, Xiaodi Wu <xiaodi.wu at gmail.com <mailto:xiaodi.wu at gmail.com>> wrote:
>> 
>> On Thu, Oct 26, 2017 at 10:57 AM, Jonathan Hull <jhull at gbis.com <mailto:jhull at gbis.com>> wrote:
>> 
>>> On Oct 26, 2017, at 8:19 AM, Xiaodi Wu <xiaodi.wu at gmail.com <mailto:xiaodi.wu at gmail.com>> wrote:
>>> 
>>> 
>>> On Thu, Oct 26, 2017 at 07:52 Jonathan Hull <jhull at gbis.com <mailto:jhull at gbis.com>> wrote:
>>>> On Oct 25, 2017, at 11:22 PM, Xiaodi Wu <xiaodi.wu at gmail.com <mailto:xiaodi.wu at gmail.com>> wrote:
>>>> 
>>>> On Wed, Oct 25, 2017 at 11:46 PM, Jonathan Hull <jhull at gbis.com <mailto: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.
>> 
>> Correct.  I view this as a good thing, because another way of saying that is: “it makes possible cases where == sometimes conforms to the rules of Equatable and sometimes doesn’t."  Under the solution I am advocating, Numeric would instead allow generic use of '==?’.
>> 
>> I suppose an argument could be made that we should extend ‘&==‘ to Numeric from FloatingPoint, but then we would end up with the Rust situation you were talking about earlier…
>> 
>> This would break any `Numeric` algorithms that currently use `==` correctly. There are useful guarantees that are common to integer `==` and IEEE floating-point `==`; namely, they each model equivalence of their respective types at roughly what IEEE calls "level 1" (as numbers, rather than as their representation or encoding). Breaking that utterly eviscerates `Numeric`.
> 
> Nope.  They would continue to work as they always have, but would have a depreciation warning on them.  The authors of those algorithms would have a full depreciation cycle to update the algorithms.  Fixits would be provided to make conversion easier.
> 
> After the depreciation cycle, Numeric would no longer guarantee a common "level 1" comparison for conforming types.

Sure there would... Semantically, NaN != NaN regardless of the underlying type, it's just that native integer types don't have a way to represent NaN so it can't come up with them.

(Unless I'm misunderstanding something again)

- Dave Sweeris
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-dev/attachments/20171026/f78644ac/attachment.html>


More information about the swift-dev mailing list