<div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Tue, Apr 26, 2016 at 10:36 AM Nicola Salmoria &lt;<a href="mailto:nicola.salmoria@gmail.com">nicola.salmoria@gmail.com</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Tue, Apr 26, 2016 at 4:28 PM, Tony Allevato <span dir="ltr">&lt;<a href="mailto:allevato@google.com" target="_blank">allevato@google.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><span><div dir="ltr">On Sun, Apr 24, 2016 at 2:57 AM Nicola Salmoria via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">&gt; &gt; func isEqual(to other: Self) -&gt;Bool<br>
&gt; &gt; func isLess(than other: Self) -&gt;Bool<br>
&gt; &gt; func isLessThanOrEqual(to other: Self) -&gt;Bool<br>
&gt;<br>
&gt; I&#39;m still not sure why these are methods instead of operators.<br>
<br>
I think this is an *excellent* choice, and I hope it is the first step to completely removing operators from protocols.<br>
<br>
IMHO throwing operators into protocols is inconsistent and confusing. Having regular methods and a single generic version of the operator that calls down on the type’s methods is clearer and guarantees that generic code can avoid ambiguities by calling the methods directly, instead of having to rely only on heavily overloaded global operators.<br></blockquote><div><br></div></span><div>I personally disagree on this point. To me, a protocol describes a set of requirements for a type to fulfill, which includes things other than methods. Just as a protocol can define initializers, properties, and associated types that a type must define in order to conform, it makes sense that a protocol would also define which operators a conforming type must support.</div></div></div></blockquote><div><br></div></div></div></div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>Well, I&#39;m not sure about that. A protocol describes what a type can do, so it&#39;s debatable whether a global function is within this scope.<br></div></div></div></div></blockquote><div><br></div><div>In my eyes, &quot;instances of a type conforming to Foo can be compared to other values using the == operator&quot; is a description of what a type can do, just as &quot;instances of a type conforming to Foo have a method named isEqual that can take another value as an argument&quot;. The only difference is how that is constructed in the language. Where we seemt o differ is that I feel that protocols should describe high-level requirements of a type (semantic), while you are arguing that they should only describe requirements that can be declared *within* them (syntactic). It&#39;s a good discussion to have, but not limited to the scope of floating point numbers.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><span style="line-height:1.5">Operators are magically special: you can declare them inside a protocol and require them to be available for conformance, even if they don&#39;t belong to the type. You can&#39;t do the same thing for normal global functions, yet conceptually global functions and operators are the same thing.</span></div></div></div></div></blockquote><div><br></div><div>I agree that this is currently an inconsistency, but perhaps only because we think of operators as functions because they&#39;re defined with &quot;func&quot;. We could either resolve the inconsistency by (1) using a different keyword, like &quot;operator&quot; (which has been discussed before, but is essentially just a visual change), (2) allowing global functions to be defined in the same way (though there would need to be a syntax change to differentiate members from globals in the protocol definitions, or (3) something else entirely that I haven&#39;t thought of.</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div><span style="line-height:1.5">Introducing a mapping between names and operators poses a few problems:</span><br></div><div><br></div><div>– IMO, they are overly verbose and add noise to the definition. This makes the language look less clean (I&#39;m getting visions of NSDecimalNumber).</div><div>– They expose two ways to accomplish the same thing (writing `x.isEqual(to: y)` and `x == y`).</div><div>– Do certain operators automatically get mapped to method names with appropriate signatures across all types, or does a conforming type still have to provide that mapping by implementing the operators separately? If it&#39;s the latter, that&#39;s extra work for the author of the type writing the protocol. If it&#39;s the former, does it make sense to automatically push these operators for all types? Should any type that has an `add` method automatically get `+` as a synonym as well? That may not be desirable.</div></div></div></blockquote><div><br></div></div></div></div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>The difference at the protocol declaration is between:<br><br>protocol Equatable {<br>    func ==(lhs: Self, rhs: Self) -&gt; Bool<br>}<br></div><div><br>and:<br><br>protocol Equatable {</div></div></div></div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><br>    func isEqual(to other: Self) -&gt; Bool<br>}<br><br></div></div></div></div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>func ==&lt;T: Equatable&gt;(lhs: T, rhs: T) -&gt; Bool {<br>    return lhs.isEqual(to: rhs)<br>}<br></div><div><br></div><div>so the latter is a bit more verbose, but arguably clearer in intent, and not different from how you would define any generic global function using a protocol, or from how you can define protocol extensions with default implementations that take advantage of the protocol&#39;s core methods.<br></div></div></div></div></blockquote><div><br></div><div>How would other global operators be defined? Would FloatingPointProtocol define operators like +&lt;T: FloatingPointProtocol&gt;, which might be different from something like +&lt;T: Matrix&gt; or +(lhs: String, rhs: String)? Or would there be a magical Addable protocol that maps +&lt;T: Addable&gt; to .add? (That&#39;s a strawman—I would hate for that protocol to exist :)</div><div><br></div><div>If the case is that individual protocols still have to define global overloads of the operators, then we haven&#39;t really achieved much except for introducing a new method into the protocol and moved the operator out, which I don&#39;t believe isn&#39;t a satisfying way of solving the problem of uniformity for protocol operators.</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><br></div><div>The difference for the conformance is between:<br></div><div><br></div><div>extension Foo : Equatable { }<br></div><div><br>func ==(lhs: Foo, rhs: Foo) -&gt; Bool {<br>    return &lt;comparison&gt;<br>}<br><br></div><div>and:<br><br></div><div>extension Bar : Equatable {<br>    func isEqual(to: Bar) -&gt; Bool {<br>        return &lt;comparison&gt;<br>    }<br>}<br></div><div><br></div><div>the former way to define the conformance can be confusing to newbies. The latter is straightforward and consistent with the usual way to adopt a protocol.<br></div></div></div></div></blockquote><div><br></div><div><span style="line-height:1.5">However, the examples you presented are not the only possible ways that we could solve this problem, and I think the community should be able to discuss options that let us keep operators as first-class citizens in protocols without bloating the protocols with unnecessary methods.</span></div><div><span style="line-height:1.5"><br></span></div><div><span style="line-height:1.5">My larger concern though is that *for this proposal specifically*, using method names instead of operators is inconsistent with Swift as it is designed today, and worse, it is making a judgment call about how operators should be expressed in protocols that deserves more discussion outside of the context of this proposal. Essentially, it would shoehorn in a design philosophy that hasn&#39;t been fully debated. (Just look at how much bikeshedding has already gone into preposition/argument labeling for isLessThanOrEqual(to:).)</span><br></div><div><span style="line-height:1.5"><br></span></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><span style="line-height:1.5">The == operator looks exactly the same at its use points, but the way how it&#39;s implemented is different.</span><br></div><div>In the former case, it&#39;s many overloads of a global function, which can stress the compiler&#39;s type inference and doesn&#39;t offer an obvious way to disambiguate in case of ambiguities.<br></div><div>In the latter case, there is only one generic definition of ==, which automatically applies to all types that conform to the protocol.<br></div><div> <br></div><div>Nicola<br></div></div></div></div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div><br></div><div>I&#39;m very supportive of the floating-point protocol proposal in general, but I feel the arithmetic and comparison operations should be exposed by operators alone and not by methods, where there is a suitable operator that has the intended meaning.</div><div><span style="line-height:1.5"><br></span></div><div><span style="line-height:1.5"> </span><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
—<br>
Nicola<br>
<br>
_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
</blockquote></div></div>
</blockquote></div></div></div></blockquote></div></div>