<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">I’m wondering if we might be trying to solve the wrong problem here.</div><div class=""><br class=""></div><div class="">Let’s look for example at part of the definition of the IntegerArithmeticType protocol (disregarding implementation details):</div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(112, 61, 170);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">public</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">protocol</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> IntegerArithmeticType</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> {</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(0, 132, 0);" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(0, 132, 0);" class=""> <span style="color: rgb(187, 44, 162);" class="">public</span> <span style="color: rgb(187, 44, 162);" class="">func</span> +(lhs: <span style="color: rgb(112, 61, 170);" class="">Self</span>, rhs: <span style="color: rgb(112, 61, 170);" class="">Self</span>) -> <span style="color: rgb(112, 61, 170);" class="">Self</span></div></div><div class=""><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class=""><br class=""></span></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">public</span> <span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">static</span> <span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">func</span> addWithOverflow(lhs: <span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Self</span>, <span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">_</span> rhs: <span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Self</span>) -> (<span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Self</span>, overflow: <span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Bool</span>)</div></div><div class="">}</div><div class=""><br class=""></div><div class="">There’s an obvious asymmetry here: + is defined as “public func”, while addWithOverflow is “public static func”.</div><div class=""><br class=""></div><div class="">Perhaps instead of extending how operators are defined, it would be more efficient to reconsider how protocol conformance should be defined.</div><div class="">It seems to me that a ‘swifter’ way to do the above would be</div><div class=""><br class=""></div><div class=""><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(112, 61, 170);" class=""><span style="color: rgb(187, 44, 162);" class="">public</span><span style="color: rgb(0, 0, 0);" class=""> </span><span style="color: rgb(187, 44, 162);" class="">protocol</span><span style="color: rgb(0, 0, 0);" class=""> IntegerArithmeticType</span><span style="color: rgb(0, 0, 0);" class=""> {</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(0, 132, 0);" class=""><br class=""></div><div style="margin: 0px; line-height: normal;" class=""><font color="#008400" face="Menlo" class=""><span style="font-size: 11px;" class=""> </span></font><span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">public</span><font color="#008400" face="Menlo" class=""><span style="font-size: 11px;" class=""> </span></font><font color="#bb2ca2" face="Menlo" class=""><span style="font-size: 11px;" class="">func</span></font><font color="#008400" face="Menlo" class=""><span style="font-size: 11px;" class=""> add(to: </span></font><span style="color: rgb(112, 61, 170); font-family: Menlo; font-size: 11px;" class="">Self</span><font color="#008400" face="Menlo" class=""><span style="font-size: 11px;" class="">) -> </span></font><span style="color: rgb(112, 61, 170); font-family: Menlo; font-size: 11px;" class="">Self</span></div></div><div class=""><span style="color: rgb(112, 61, 170);" class=""><br class=""></span></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""> <span style="color: rgb(187, 44, 162);" class="">public</span> <span style="color: rgb(187, 44, 162);" class="">func</span> addWithOverflow(to: <span style="color: rgb(112, 61, 170);" class="">Self</span>) -> (<span style="color: rgb(112, 61, 170);" class="">Self</span>, overflow: <span style="color: rgb(112, 61, 170);" class="">Bool</span>)</div></div><div class="">}</div></div><div class=""><br class=""></div><div class="">and then generic operators can simply be defined once at global scope:</div><div class=""><br class=""></div><div class="">public func +<T: IntegerArithmeticType>(lhs: T, rhs: T) -> T {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>return lhs.add(hrs)</div><div class="">}</div><div class=""><br class=""></div><div class=""><div class="">public func &+<T: IntegerArithmeticType>(lhs: T, rhs: T) -> T {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>return lhs.addWithOverflow(hrs).0</div><div class="">}</div></div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">Equatable and Comparable have similar asymmetries:</div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(0, 132, 0);" class="">/// Instances of conforming types can be compared for value equality</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(0, 132, 0);" class="">/// using operators `==` and `!=`.</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(0, 132, 0);" class="">///</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(0, 132, 0);" class="">/// When adopting `Equatable`, only the `==` operator is required to be</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(0, 132, 0);" class="">/// implemented. The standard library provides an implementation for `!=`.</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(187, 44, 162);" class="">public<span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> </span>protocol<span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> Equatable {</span></div></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">public</span> <span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">func</span> ==(lhs: <span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Self</span>, rhs: <span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Self</span>) -> <span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Bool</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class="">}</div></div><div class=""><br class=""></div><div class="">so we need to define ==, but not != because it’s derived from the former.</div><div class="">Again, the cause of the inconsistency is the requirement to define the operator as part of the protocol conformance. If it was done like this, it might seem simpler and more symmetrical:</div><div class=""><br class=""></div><div class=""><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(187, 44, 162);" class="">public<span style="color: rgb(0, 0, 0);" class=""> </span>protocol<span style="color: rgb(0, 0, 0);" class=""> Equatable {</span></div></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""> <span style="color: rgb(187, 44, 162);" class="">public</span> <span style="color: rgb(187, 44, 162);" class="">func</span> equals(other: <span style="color: rgb(112, 61, 170);" class="">Self</span>) -> <span style="color: rgb(112, 61, 170);" class="">Bool</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class="">}</div></div></div><div class=""><br class=""></div><div class=""><div class="">public func ==<T: Equatable>(lhs: T, rhs: T) -> T {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>return lhs.equals(hrs)</div><div class="">}</div></div><div class=""><div class=""><div class="">public func !=<T: Equatable>(lhs: T, rhs: T) -> T {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>return !lhs.equals(hrs)</div><div class="">}</div></div></div><div class=""><br class=""></div><div class="">Nicola</div><div class=""><br class=""></div>
> Hello.<br class="">> <br class="">> The proposal can be also read <a href="athttps://gist.github.com/vmartinelli/67d6ad234c7a4e14f8d5" class="">athttps://gist.github.com/vmartinelli/67d6ad234c7a4e14f8d5</a><br class="">> <br class="">> Original thread:https://<a href="http://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160125/008508.html" class="">lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160125/008508.html</a><br class="">> <br class="">> Opinions, comments and corrections (including on English grammar) are all welcome. :-)<br class="">> <br class="">> -Van<br class="">> <br class="">> ---------<br class="">> <br class="">> Instance Operators<br class="">> Proposal:SE-NNNN(<a href="https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-instance-operators.md" class="">https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-instance-operators.md</a>)<br class="">> Author:Vanderlei Martinelli(<a href="https://github.com/vmartinelli" class="">https://github.com/vmartinelli</a>)<br class="">> Status:Awaiting review<br class="">> Review manager: TBD<br class="">> <br class="">> Introduction<br class="">> <br class="">> The proposal aims to move operator implementation from the global and static scope into extension/struct/class instance scope.<br class="">> <br class="">> <br class="">> Swift-evolution thread:link to the discussion thread for that proposal(<a href="https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160125/008508.html" class="">https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160125/008508.html</a>)<br class="">> <br class="">> Motivation<br class="">> <br class="">> When writing the protocol interface the operator is declarated inside the scope of that protocol, but its implementation has to be static and global. This, besides being inconsistent, might not the behaviour expected by programmers coming from other languages that have some kind of support for interface/protocol and operator implementation.<br class="">> <br class="">> <br class="">> Example:<br class="">> <br class="">> // MARK: - protocolpublicprotocolMyDoubleType {publicfuncsomeUsefulFunction()publicfunc*(lhs:Self, rhs:Self)->Selfpublicpostfixfunc++(inoutx:Self)->Self }// MARK: - implementationextensionDouble: MyDoubleType {publicfuncsomeUsefulFunction() {// ...}// we cannot implement the operators here...}// ... but have to implement them herepublicfunc*(lhs:Double, rhs:Double)->Double{returnlhs.multipliedBy(rhs) }publicpostfixfunc++(inoutx:Double)->Double{<span class="Apple-converted-space"> </span> x+=1.0returnx }<br class="">> <br class="">> <br class="">> Also the current implementation does not leave much room for future expansion in the use of operators (such as conversion between values, for example).<br class="">> <br class="">> Proposed solution<br class="">> <br class="">> Move the operator implementation into the extension/struct/class scope and turn operator funcs into instance funcs, using theoperatorkeyword.<br class="">> <br class="">> Detailed design<br class="">> Protocol conformance<br class="">> <br class="">> After the change the above code can be written like the example bellow.<br class="">> <br class="">> // MARK: - protocolpublicprotocolMyDoubleType {publicfuncsomeUsefulFunction()publicoperator*(rhs:Self)->Selfpublicmutatingpostfixoperator++()->Self}// MARK: - implementationextensionDouble: MyDoubleType {publicfuncsomeUsefulFunction() {// ...}publicoperator*(rhs:Double)->Double{returnself.multipliedBy(rhs)<span class="Apple-converted-space"> </span> }publicmutatingpostfixoperator++()->Double{self+=1.0returnself} }<br class="">> <br class="">> Operator funcs everywhere<br class="">> <br class="">> An operator does not have to be implemented only to conform to a protocol, however. It can be also be implemented in any other place where a common func is. This means that even the current form can be supported.<br class="">> <br class="">> Operator internal names<br class="">> <br class="">> Perhaps because of the internal implementation of Swift, operators have to have names to be handled. The suggestion is to adopt__operator__GreaterThanOrEqualfor a>=operator, as example. The operator introduction would be:<br class="">> <br class="">> infixoperator>={associativitynoneprecedence130name"GreaterThanOrEqual"}<br class="">> <br class="">> <br class="">> So the code will be written like this...<br class="">> <br class="">> structMyStruct {operator>=(other: MyStruct)->Bool{return...} }<br class="">> <br class="">> <br class="">> ... but translated internally to this:<br class="">> <br class="">> structMyStruct {func__operator__GreaterThanOrEqual(other: MyStruct)->Bool{return...} }<br class="">> <br class="">> Impact on existing code<br class="">> <br class="">> Since after this change an operator can be implemented in any other place where a common func can be, the current implementation may continue to exist, but marked as deprecated with a compiler/analyser warning.<br class="">> <br class="">> <br class="">> Also thefunckeyword would be deprecated for operators as well, using theoperatorto declare/implement an operator func.<br class="">> <br class="">> Alternatives considered<br class="">> Status quo<br class="">> <br class="">> Leave things as they are. Even being inconsistent or not allowing new possibilities that instance operators will bring.<br class="">> <br class="">> Static implementation inside extension/struct/class scope<br class="">> <br class="">> This is the way operators are implemented in C#, for example. The change would be only aesthetic. The functionality would remain the same as today.<br class="">> <br class="">> <br class="">> As the types may differ from protocol/structure/class, this would allow state within the scope of operators that have nothing to do with that type. Not a good thing. In this case it might be better to keep things as they are.<br class="">> <br class="">> <br class="">> Example:<br class="">> <br class="">> // MARK: - protocolpublicprotocolMyDoubleType {publicfuncsomeUsefulFunction()publicstaticoperator*(lhs:Self, rhs:Self)->Selfpublicstaticoperator/(lhs:Int64, rhs:Int64)->Int64// what?publicstaticpostfixoperator++(inoutx:Self)->Self}// MARK: - implementationextensionDouble: MyDoubleType {publicfuncsomeUsefulFunction() {// ...}publicstaticoperator*(lhs:Double, rhs:Double)->Double{returnlhs.multipliedBy(rhs)<span class="Apple-converted-space"> </span> }// this should be implemented inside a Int64 type, not here...publicstaticoperator/(lhs:Int64, rhs:Int64)->Int64{// ...}publicstaticpostfixoperator++(inoutx:Double)->Double{<span class="Apple-converted-space"> </span> <span class="Apple-converted-space"> </span> x+=1.0returnx<span class="Apple-converted-space"> </span> } }<br class="">> <br class="">> <br class="">> <br class="">><span class="Apple-converted-space"> </span>
</body></html>