<div dir="ltr">On Thu, Oct 26, 2017 at 1:30 PM, Jonathan Hull <span dir="ltr"><<a href="mailto:jhull@gbis.com" target="_blank">jhull@gbis.com</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word">Now you are just being rude. We all want Swift to be awesome… let’s try to keep things civil.</div></blockquote><div><br></div><div>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:</div><div><br></div><div>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?</div><div><br></div><div>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?</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div></div><div>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.</div><div><br></div><div>For FloatingPoint, ‘(a &== b) == true’ would mimic the current behavior (bugs and all). It may not hold for all types.</div></div></blockquote><div><br></div><div>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 `&==`.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div>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.<div><br></div><div>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.</div></div></div></blockquote><div><br></div><div>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`.</div><div><br></div><div>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.</div><div><br></div><div>Both concepts must be exposed in a protocol-based manner to accommodate all use cases. It will not do to say that exposing both concepts will confuse the user, because the fact remains that both concepts are already and unavoidably exposed, but sometimes without a way to express the distinction in code or any documentation about it. Disappearing the notion of partial equivalence from protocols removes legitimate use cases.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div><div><div class="h5"><div><div><blockquote type="cite"><div>On Oct 26, 2017, at 11:01 AM, Xiaodi Wu <<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a>> wrote:</div><br class="m_-447657632371146186Apple-interchange-newline"><div><div dir="ltr">On Thu, Oct 26, 2017 at 11:50 AM, Jonathan Hull <span dir="ltr"><<a href="mailto:jhull@gbis.com" target="_blank">jhull@gbis.com</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div><div class="m_-447657632371146186h5"><br><div><blockquote type="cite"><div>On Oct 26, 2017, at 9:40 AM, Xiaodi Wu <<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a>> wrote:</div><br class="m_-447657632371146186m_1160915223428538344Apple-interchange-newline"><div><div dir="ltr" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px">On Thu, Oct 26, 2017 at 11:38 AM, Jonathan Hull<span class="m_-447657632371146186m_1160915223428538344Apple-converted-space"> </span><span dir="ltr"><<a href="mailto:jhull@gbis.com" target="_blank">jhull@gbis.com</a>></span><span class="m_-447657632371146186m_1160915223428538344Apple-converted-space"> </span>wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div><div class="m_-447657632371146186m_1160915223428538344h5"><br><div><blockquote type="cite"><div>On Oct 26, 2017, at 9:34 AM, Xiaodi Wu <<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a>> wrote:</div><br class="m_-447657632371146186m_1160915223428538344m_2112110288747036163Apple-interchange-newline"><div><div dir="ltr" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px">On Thu, Oct 26, 2017 at 10:57 AM, Jonathan Hull<span class="m_-447657632371146186m_1160915223428538344m_2112110288747036163Apple-converted-space"> </span><span dir="ltr"><<a href="mailto:jhull@gbis.com" target="_blank">jhull@gbis.com</a>></span><span class="m_-447657632371146186m_1160915223428538344m_2112110288747036163Apple-converted-space"> </span>wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><br><div><span><blockquote type="cite"><div>On Oct 26, 2017, at 8:19 AM, Xiaodi Wu <<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a>> wrote:</div><br class="m_-447657632371146186m_1160915223428538344m_2112110288747036163m_-286131493490082862m_-3464844430018851624Apple-interchange-newline"><div><div dir="auto" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br class="m_-447657632371146186m_1160915223428538344m_2112110288747036163m_-286131493490082862m_-3464844430018851624Apple-interchange-newline">On Thu, Oct 26, 2017 at 07:52 Jonathan Hull <<a href="mailto:jhull@gbis.com" target="_blank">jhull@gbis.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div><blockquote type="cite"><div>On Oct 25, 2017, at 11:22 PM, Xiaodi Wu <<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a>> wrote:</div><br class="m_-447657632371146186m_1160915223428538344m_2112110288747036163m_-286131493490082862m_-3464844430018851624m_-203124280784081011Apple-interchange-newline"><div><div>On Wed, Oct 25, 2017 at 11:46 PM, Jonathan Hull<span class="m_-447657632371146186m_1160915223428538344m_2112110288747036163m_-286131493490082862m_-3464844430018851624Apple-converted-space"> </span><span><<a href="mailto:jhull@gbis.com" target="_blank">jhull@gbis.com</a>></span><span class="m_-447657632371146186m_1160915223428538344m_2112110288747036163m_-286131493490082862m_-3464844430018851624Apple-converted-space"> </span>wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word">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.<div><br></div><div>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 ‘&==‘.</div></div></blockquote><div><br></div><div>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. </div></div></div></div></div></blockquote><div><br></div></div></div><div style="word-wrap:break-word"><div><div>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.</div></div></div><div style="word-wrap:break-word"><div><div><br></div><br><blockquote type="cite"><div><div><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div>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.</div></div></blockquote><div><br></div><div>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.</div></div></div></div></div></blockquote><div><br></div><div><br></div></div></div><div style="word-wrap:break-word"><div><div>#1 from my previous email (shown again here):</div></div></div><div style="word-wrap:break-word"><div><div><blockquote type="cite"><div><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div><div><div class="m_-447657632371146186m_1160915223428538344m_2112110288747036163m_-286131493490082862m_-3464844430018851624m_-203124280784081011m_-4014199803616980042h5"><div><div><blockquote type="cite"><div><div><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">Currently, I think we should do 3 things:<br><br>1) Create a new protocol with a partial equivalence relation with signature of (T, T)->Bool? and automatically conform Equatable things to it<br>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)<br>3) Provide an '&==‘ relation on Float, etc… (without a protocol) with the native Float IEEE comparison</blockquote></div></div></div></div></blockquote></div></div></div></div></div></div></blockquote></div></div></div></blockquote></div><div><br></div></div></div><div style="word-wrap:break-word"><div><div>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.</div></div></div></blockquote><div dir="auto" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br></div><div dir="auto" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px">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.</div></div></blockquote><div><br></div></span><div>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 '==?’.</div><div><br></div></div>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…<div></div></div></blockquote></div><br></div><div class="gmail_extra">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`.</div></div></div></blockquote><br></div></div></div><div>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.</div></div></blockquote><div><br></div><div>After the depreciation cycle, Numeric would no longer guarantee a common "level 1" comparison for conforming types.</div></div></div></div></div></blockquote><br></div></div></div><div>It would, using ==?, you would just be forced to deal with the possibility of the Equality relation not holding. '(a ==? b) == true' would mimic the current behavior.</div></div></blockquote><div><br></div><div>What are the semantic guarantees required of `==?` such that this would be guaranteed to be the current behavior? How would this be implementable without being so costly that, in practice, no generic numeric algorithms would ever use such a facility?</div><div><br></div><div>Moreover, if `(a ==? b) == true` guarantees the current behavior for all types, and all currently Equatable types will conform to this protocol, haven't you just reproduced the problem seen in Rust's `PartialEq`, only now with clumsier syntax and poorer performance?</div><div><br></div><div>Is it the _purpose_ of this design to make it clumsier and less performant so people don't use it? If so, to the extent that it is an effective deterrent, haven't you created a deterrent to the use of Numeric to an exactly equal extent?</div><div><br></div></div></div></div>
</div></blockquote></div><br></div></div></div></div></div></blockquote></div><br></div></div>