[swift-dev] Rationalizing FloatingPoint conformance to Equatable

Greg Parker gparker at apple.com
Thu Oct 26 16:57:01 CDT 2017

> On Oct 26, 2017, at 11:47 AM, Xiaodi Wu via swift-dev <swift-dev at swift.org> wrote:
> On Thu, Oct 26, 2017 at 1:30 PM, Jonathan Hull <jhull at gbis.com <mailto:jhull at gbis.com>> wrote:
> Now you are just being rude. We all want Swift to be awesome… let’s try to keep things civil.
> Sorry if my reply came across that way! That wasn't at all the intention. I really mean to ask you those questions and am interested in the answers:
> Unless I misunderstand, you're arguing that your proposal is superior to Rust's design because of a new operator that returns `Bool?` instead of `Bool`; if so, how is it that you haven't reproduced Rust's design problem, only with the additional syntax involved in unwrapping the result?
> And if, as I understand, your argument is that your design is superior to Rust's *because* it requires unwrapping, then isn't the extent to which people will avoid using the protocol unintentionally also equally and unavoidably the same extent to which it makes Numeric more cumbersome?
> You said it was impossible, so I gave you a very quick example showing that the current behavior was still possible.  I wasn’t recommending that everyone should only ever use that example for all things.
> For FloatingPoint, ‘(a &== b) == true’ would mimic the current behavior (bugs and all). It may not hold for all types.
> No, the question was how it would be possible to have these guarantees hold for `Numeric`, not merely for `FloatingPoint`, as the purpose is to use `Numeric` for generic algorithms. This requires additional semantic guarantees on what you propose to call `&==`.

Would something like this work?

Numeric.== -> Bool 
traps on NaN etc.

Numeric.==? -> Bool? 
returns nil on NaN etc. You likely don't want this unless you know something about floating-point.

Numeric.&== -> Bool
is IEEE equality. You should not use this unless you are a floating-point expert.

The experts can get high performance or sophisticated numeric behavior. The rest of us who naïvely use == get a relatively foolproof floating-point model. (There is no difference among these three operators for fixed-size integers, of course.)

This is analogous to what Swift does with integer overflow. I would further argue the other Numeric operators like + should be extended to the same triple of trap or optional or just-do-it. We already have two of those three operators for integer addition after all.

Numeric.+ -> T
traps on FP NaN and integer overflow

Numeric.+? -> T?
returns nil on FP NaN and integer overflow

Numeric.&+ -> T
performs FP IEEE addition and integer wraparound

> The whole point is that you have to put thought into how you want to deal with the optional case where the relation’s guarantees have failed.
> If you need full performance, then you would have separate overrides on Numeric for members which conform to FloatingPoint (where you could use &==) and Equatable (where you could use ==). As you get more generic, you lose opportunities for optimization. That is just the nature of generic code. The nice thing about Swift is that you have an opportunity to specialize if you want to optimize more. Once things like conditional conformances come online, all of this will be nicer, of course.
> This is a non-starter then. Protocols must enable useful generic code. What you're basically saying is that you do not intend for it to be possible to use methods on `Numeric` to ask about level 1 equivalence in a way that would not be prohibitively expensive. This, again, eviscerates the purpose of `Numeric`.

I'm not sure that there is a performance problem. If your compiled code is actually making calls to generic comparison functions then you have already lost the high performance war. Any place where the compiler knows enough to use a specialized comparison function should also be a place where the compiler can optimize away unnecessary floating-point checks.

Let me make an analogous objection to the current Numerics design. How do you get the highest performance addition operator in a generic context? Currently you can't, because Numeric.+ checks for integer overflow.

> The point I'm making here, again, is that there are legitimate uses for `==` guaranteeing partial equivalence in the generic context. The approximation being put forward over and over is that generic code always requires full equivalence and concrete floating-point code always requires IEEE partial equivalence. That is _not true_. Some generic code (for instance, that which uses `Numeric`) relies on partial equivalence semantics and some floating-point code can nonetheless benefit from a notion of full equivalence.

I agree that providing a way to get IEEE equality in a generic context is useful. I am not convinced that Numeric.== -> Bool is the right place to provide it.

Greg Parker     gparker at apple.com <mailto:gparker at apple.com>     Runtime Wrangler

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

More information about the swift-dev mailing list