<div dir="ltr">I like the direction this takes things! Thanks for hammering out a proposal to get the ball rolling.<div><br></div><div>-Shawn<br><br><div class="gmail_quote"><div dir="ltr">On Mon, May 2, 2016 at 9:51 AM Tony Allevato via swift-evolution <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">I've written a proposal to formalize some of the discussion that was had over in the thread for the `FloatingPoint` protocol proposal regarding improvements to operator requirements in protocols that do not require named methods be added to the protocol and conforming types. Thanks to everyone who was participating in that discussion!<div><br></div><div>The proposal can be viewed in <a href="https://github.com/apple/swift-evolution/pull/283" target="_blank">this pull request</a> and is pasted below.</div><div><br></div><div><br></div><div><h1 style="font-size:2.25em;margin-right:0px;margin-bottom:16px;margin-left:0px;line-height:1.2;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';margin-top:0px!important">Improving operator requirements in protocols</h1><ul style="padding-left:2em;margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px"><li>Proposal: <a href="https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-improving-operators-in-protocols.md" style="color:rgb(64,120,192);text-decoration:none;background-color:transparent" target="_blank">SE-NNNN</a></li><li>Author(s): <a href="https://github.com/allevato" style="color:rgb(64,120,192);text-decoration:none;background-color:transparent" target="_blank">Tony Allevato</a></li><li>Status: TBD</li><li>Review manager: TBD</li></ul><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol'"><a href="https://github.com/allevato/swift-evolution/blob/master/proposals/0000-improving-operators-in-protocols.md#introduction" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1;background-color:transparent" target="_blank"></a>Introduction</h2><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">When a type conforms to a protocol that declares an operator as a requirement, that operator must be implemented as a global function defined outside of the conforming type. This can lead both to user confusion and to poor type checker performance since the global namespace is overcrowded with a large number of operator overloads. This proposal mitigates both of those issues by proposing that operators in protocols be declared statically (to change and clarify where the conforming type implements it) and use generic global trampoline operators (to reduce the global overload set that the type checker must search).</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">Swift-evolution thread: <a href="https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160425/015807.html" style="color:rgb(64,120,192);text-decoration:none;background-color:transparent" target="_blank">Discussion about operators and protocols in the context of <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">FloatingPoint</code></a></p><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol'"><a href="https://github.com/allevato/swift-evolution/blob/master/proposals/0000-improving-operators-in-protocols.md#motivation" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1;background-color:transparent" target="_blank"></a>Motivation</h2><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">The proposal came about as a result of discussion about <a href="https://github.com/apple/swift-evolution/blob/master/proposals/0067-floating-point-protocols.md" style="color:rgb(64,120,192);text-decoration:none;background-color:transparent" target="_blank">SE-0067: Enhanced Floating Point Protocols</a>. To implement the numerous arithmetic and comparison operators, this protocol defined named instance methods for them and then implemented the global operator functions to delegate to them. For example,</p><div style="margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;margin-top:0px;margin-bottom:0px;font-stretch:normal;line-height:1.45;padding:16px;overflow:auto;border-radius:3px;word-wrap:normal;word-break:normal;background-color:rgb(247,247,247)"><span style="color:rgb(167,29,93)">public</span> <span style="color:rgb(167,29,93)">protocol</span> FloatingPoint {
<span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">adding</span>(rhs: <span style="color:rgb(167,29,93)">Self</span>) <span style="color:rgb(167,29,93)">-></span> Self
<span style="color:rgb(150,152,150)">// and others</span>
}
<span style="color:rgb(167,29,93)">public</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">+</span> <T: FloatingPoint>(lhs: T, rhs: T) <span style="color:rgb(167,29,93)">-></span> T {
<span style="color:rgb(167,29,93)">return</span> lhs<span style="color:rgb(167,29,93)">.</span>adding(rhs)
}</pre></div><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">One of the motivating factors for these named methods was to make the operators generic and reduce the number of concrete global overloads, which would improve the type checker's performance compared to individual concrete overloads for each conforming type. Some concerns were raised about the use of named methods:</p><ul style="padding-left:2em;margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px"><li>They bloat the public interface. Every floating point type would expose mutating and non-mutating methods for each arithmetic operation, as well as non-mutating methods for the comparisons. We don't expect users to actually call these methods directly but they must be present in the public interface because they are requirements of the protocol. Therefore, they would clutter API documentation and auto-complete lists and make the properties and methods users actually want to use less discoverable.</li><li>Swift's naming guidelines encourage the use of "terms of art" for naming when it is appropriate. In this case, the operator itself is the term of art. It feels odd to elevate <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">(2.0).adding(2.0).isEqual(to: 4.0)</code> to the same first-class status as <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">2.0 + 2.0 == 4.0</code>; this is the situation that overloaded operators were made to prevent.</li><li>Devising good names for the operators is tricky; the swift-evolution list had a fair amount of bikeshedding about the naming and preposition placement of <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">isLessThanOrEqual(to:)</code> in order to satisfy API guidelines, for example.</li><li>Having both an <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">adding</code> method and a <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">+</code> operator provides two ways for the user to do the same thing. This may lead to confusion if users think that the two ways of adding have slightly different semantics.</li></ul><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">Some contributors to the discussion list have expressed concerns about operators being members of protocols at all. I feel that removing them entirely would be a step backwards for the Swift language; a protocol is not simply a list of properties and methods that a type must implement, but rather a higher-level set of requirements. Just as properties, methods, and associated types are part of that requirement set, it makes sense that an arithmetic type, for example, would declare arithmetic operators among its requirements as well.</p><h3 style="margin-top:1em;margin-bottom:16px;line-height:1.43;font-size:1.5em;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol'"><a href="https://github.com/allevato/swift-evolution/blob/master/proposals/0000-improving-operators-in-protocols.md#inconsistency-in-the-current-operator-design-with-protocols" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1.2;background-color:transparent" target="_blank"></a>Inconsistency in the current operator design with protocols</h3><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">When a protocol declares an operator as a requirement, that requirement is located <em>inside</em> the protocol definition. For example, consider <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Equatable</code>:</p><div style="margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;margin-top:0px;margin-bottom:0px;font-stretch:normal;line-height:1.45;padding:16px;overflow:auto;border-radius:3px;word-wrap:normal;word-break:normal;background-color:rgb(247,247,247)"><span style="color:rgb(167,29,93)">protocol</span> <span style="color:rgb(0,134,179)">Equatable</span> {
<span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">==</span>(lhs: <span style="color:rgb(167,29,93)">Self</span>, rhs: <span style="color:rgb(167,29,93)">Self</span>) <span style="color:rgb(167,29,93)">-></span> <span style="color:rgb(0,134,179)">Bool</span>
}</pre></div><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">However, since operators are global functions, the actual implementation of that operator for a conforming type must be made <em>outside</em> the type definition. This can look particularly odd when extending an existing type to conform to an operator-only protocol:</p><div style="margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;margin-top:0px;margin-bottom:0px;font-stretch:normal;line-height:1.45;padding:16px;overflow:auto;border-radius:3px;word-wrap:normal;word-break:normal;background-color:rgb(247,247,247)"><span style="color:rgb(167,29,93)">extension</span> Foo: <span style="color:rgb(0,134,179)">Equatable</span> {}
<span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">==</span>(lhs: Foo, rhs: Foo) <span style="color:rgb(167,29,93)">-></span> <span style="color:rgb(0,134,179)">Bool</span> {
<span style="color:rgb(150,152,150)">// Implementation goes here</span>
}</pre></div><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">This is an odd inconsistency in the Swift language, driven by the fact that operators must be global functions. What's worse is that every concrete type that conforms to <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Equatable</code> must provide the operator function at global scope. As the number of types conforming to this protocol increases, so does the workload of the compiler to perform type checking.</p><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol'"><a href="https://github.com/allevato/swift-evolution/blob/master/proposals/0000-improving-operators-in-protocols.md#proposed-solution" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1;background-color:transparent" target="_blank"></a>Proposed solution</h2><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">The solution described below is an <em>addition</em> to the Swift language. This document does <em>not</em> propose that the current way of defining operators be removed or changed at this time. Rather, we describe an addition that specifically provides improvements for protocol operator requirements.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">When a protocol wishes to declare operators that conforming types must implement, we propose adding the ability to declare operator requirements as static members of the protocol:</p><div style="margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;margin-top:0px;margin-bottom:0px;font-stretch:normal;line-height:1.45;padding:16px;overflow:auto;border-radius:3px;word-wrap:normal;word-break:normal;background-color:rgb(247,247,247)"><span style="color:rgb(167,29,93)">protocol</span> <span style="color:rgb(0,134,179)">Equatable</span> {
<span style="color:rgb(167,29,93)">static</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">==</span>(lhs: <span style="color:rgb(167,29,93)">Self</span>, rhs: <span style="color:rgb(167,29,93)">Self</span>) <span style="color:rgb(167,29,93)">-></span> <span style="color:rgb(0,134,179)">Bool</span>
}</pre></div><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">Then, the protocol author is responsible for providing a generic global <em>trampoline</em> operator that is constrained by the protocol type and delegates to the static operator on that type:</p><div style="margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;margin-top:0px;margin-bottom:0px;font-stretch:normal;line-height:1.45;padding:16px;overflow:auto;border-radius:3px;word-wrap:normal;word-break:normal;background-color:rgb(247,247,247)"><span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">==</span> <T: <span style="color:rgb(0,134,179)">Equatable</span>>(lhs: T, rhs: T) <span style="color:rgb(167,29,93)">-></span> <span style="color:rgb(0,134,179)">Bool</span> {
<span style="color:rgb(167,29,93)">return</span> T<span style="color:rgb(167,29,93)">.==</span>(lhs, rhs)
}</pre></div><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">Types conforming to a protocol that contains static operators would implement the operators as static methods defined<em>within</em> the type:</p><div style="margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;margin-top:0px;margin-bottom:0px;font-stretch:normal;line-height:1.45;padding:16px;overflow:auto;border-radius:3px;word-wrap:normal;word-break:normal;background-color:rgb(247,247,247)"><span style="color:rgb(167,29,93)">struct</span> Foo: <span style="color:rgb(0,134,179)">Equatable</span> {
<span style="color:rgb(167,29,93)">let</span> value: <span style="color:rgb(0,134,179)">Int</span>
<span style="color:rgb(167,29,93)">static</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">==</span>(lhs: Foo, rhs: Foo) <span style="color:rgb(167,29,93)">-></span> <span style="color:rgb(0,134,179)">Bool</span> {
<span style="color:rgb(167,29,93)">return</span> lhs<span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">value</span> <span style="color:rgb(167,29,93)">==</span> rhs<span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">value</span>
}
}
<span style="color:rgb(167,29,93)">let</span> f1 <span style="color:rgb(167,29,93)">=</span> Foo(value: <span style="color:rgb(0,134,179)">5</span>)
<span style="color:rgb(167,29,93)">let</span> f2 <span style="color:rgb(167,29,93)">=</span> Foo(value: <span style="color:rgb(0,134,179)">10</span>)
<span style="color:rgb(167,29,93)">let</span> eq <span style="color:rgb(167,29,93)">=</span> (f1 <span style="color:rgb(167,29,93)">==</span> f2)</pre></div><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">When the compiler sees an equality expression between two <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Foo</code>s like the one above, it will call the global <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">== <T: Equatable></code> function. Since <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">T</code> is bound to the type <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Foo</code> in this case, that function simply delegates to the static method<code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Foo.==</code>, which performs the actual comparison.</p><h3 style="margin-top:1em;margin-bottom:16px;line-height:1.43;font-size:1.5em;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol'"><a href="https://github.com/allevato/swift-evolution/blob/master/proposals/0000-improving-operators-in-protocols.md#benefits-of-this-approach" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1.2;background-color:transparent" target="_blank"></a>Benefits of this approach</h3><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">By using the name of the operator itself as the method, this approach avoids bloating the public interfaces of protocols and conforming types with additional named methods, reducing user confusion. This also will lead to better consistency going forward, as various authors of such protocols will not be providing their own method names.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">For a particular operator, this approach also reduces the number of global instances of that operator. Instead of there being one instance per concrete type conforming to that protocol, there is a single generic one per protocol. This should have a positive impact on type checker performance by splitting the lookup of an operator's implementation from searching through a very large set to searching through a much smaller set to find the generic trampoline and then using the bound type to quickly resolve the actual implementation.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">Similarly, this behavior allows users to be more explicit when referring to operator functions as first-class operations. Passing an operator function like <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">+</code> to a generic algorithm will still work with the trampoline operators, but in situations where type inference fails and the user needs to be more explicit about the types, being able to write <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">T.+</code> is a cleaner and unambiguous shorthand compared to casting the global <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">+</code> to the appropriate function signature type.</p><h3 style="margin-top:1em;margin-bottom:16px;line-height:1.43;font-size:1.5em;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol'"><a href="https://github.com/allevato/swift-evolution/blob/master/proposals/0000-improving-operators-in-protocols.md#other-kinds-of-operators-prefix-postfix-assignment" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1.2;background-color:transparent" target="_blank"></a>Other kinds of operators (prefix, postfix, assignment)</h3><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">Static operator methods have the same signatures as their global counterparts. So, for example, prefix and postfix operators as well as assignment operators would be defined the way one would expect:</p><div style="margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;margin-top:0px;margin-bottom:0px;font-stretch:normal;line-height:1.45;padding:16px;overflow:auto;border-radius:3px;word-wrap:normal;word-break:normal;background-color:rgb(247,247,247)"><span style="color:rgb(167,29,93)">protocol</span> SomeProtocol {
<span style="color:rgb(167,29,93)">static</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">+=</span>(lhs: <span style="color:rgb(121,93,163)">inout</span> <span>Self</span>, rhs: <span style="color:rgb(167,29,93)">Self</span>)
<span style="color:rgb(167,29,93)">static</span> <span style="color:rgb(167,29,93)">prefix</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">~</span>(value: <span style="color:rgb(167,29,93)">Self</span>) <span style="color:rgb(167,29,93)">-></span> Self
<span style="color:rgb(150,152,150)">// This one is deprecated, of course, but used here just to serve as an</span>
<span style="color:rgb(150,152,150)">// example.</span>
<span style="color:rgb(167,29,93)">static</span> <span style="color:rgb(167,29,93)">postfix</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">++</span>(value: <span style="color:rgb(121,93,163)">inout</span> <span>Self</span>) <span style="color:rgb(167,29,93)">-></span> Self
}
<span style="color:rgb(150,152,150)">// Trampolines</span>
<span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">+=</span> <T: SomeProtocol>(lhs: <span style="color:rgb(121,93,163)">inout</span> <span>T</span>, <span style="color:rgb(121,93,163)">rhs</span> <span>T</span>) {
T<span style="color:rgb(167,29,93)">.+=</span>(<span style="color:rgb(167,29,93)">&</span>lhs, rhs)
}
<span style="color:rgb(167,29,93)">prefix</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">~</span> <T: SomeProtocol>(value: T) <span style="color:rgb(167,29,93)">-></span> T {
<span style="color:rgb(167,29,93)">return</span> T<span style="color:rgb(167,29,93)">.~</span>(value)
}
<span style="color:rgb(167,29,93)">postfix</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">++</span> <T: SomeProtocol>(value: <span style="color:rgb(121,93,163)">inout</span> <span>T</span>) <span style="color:rgb(167,29,93)">-></span> T {
<span style="color:rgb(167,29,93)">return</span> T<span style="color:rgb(167,29,93)">.++</span>(<span style="color:rgb(167,29,93)">&</span>value)
}</pre></div><h3 style="margin-top:1em;margin-bottom:16px;line-height:1.43;font-size:1.5em;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol'"><a href="https://github.com/allevato/swift-evolution/blob/master/proposals/0000-improving-operators-in-protocols.md#open-issue-class-types-and-inheritance" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1.2;background-color:transparent" target="_blank"></a>Open issue: Class types and inheritance</h3><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">While this approach works well for value types, these static operators may not work as expected for class types when inheritance is involved, and more work may be needed here.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">We can currently model the behavior we'd like to achieve by using a named <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">eq</code> method instead of the operator itself. (Note that we are <em>not</em> proposing that the function be named <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">eq</code> in the final design; this was done simply to perform the experiment with today's compiler.) Then we implement both the new method and the current <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">==</code> operator and compare their behaviors. For example:</p><div style="margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;margin-top:0px;margin-bottom:0px;font-stretch:normal;line-height:1.45;padding:16px;overflow:auto;border-radius:3px;word-wrap:normal;word-break:normal;background-color:rgb(247,247,247)"><span style="color:rgb(167,29,93)">protocol</span> ProposedEquatable {
<span style="color:rgb(167,29,93)">static</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">eq</span>(lhs: <span style="color:rgb(167,29,93)">Self</span>, <span style="color:rgb(121,93,163)">_</span> <span>rhs</span>: <span style="color:rgb(167,29,93)">Self</span>) <span style="color:rgb(167,29,93)">-></span> <span style="color:rgb(0,134,179)">Bool</span>
}
<span style="color:rgb(167,29,93)">class</span> Base: ProposedEquatable, <span style="color:rgb(0,134,179)">Equatable</span> {
<span style="color:rgb(167,29,93)">static</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">eq</span>(lhs: Base, <span style="color:rgb(121,93,163)">_</span> <span>rhs</span>: Base) <span style="color:rgb(167,29,93)">-></span> <span style="color:rgb(0,134,179)">Bool</span> {
<span style="color:rgb(0,134,179)">print</span>(<span style="color:rgb(24,54,145)"><span>"</span>Base.eq<span>"</span></span>)
<span style="color:rgb(167,29,93)">return</span> <span style="color:rgb(0,134,179)">true</span>
}
}
<span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">==</span>(lhs: Base, rhs: Base) <span style="color:rgb(167,29,93)">-></span> <span style="color:rgb(0,134,179)">Bool</span> {
<span style="color:rgb(0,134,179)">print</span>(<span style="color:rgb(24,54,145)"><span>"</span>==(Base, Base)<span>"</span></span>)
<span style="color:rgb(167,29,93)">return</span> <span style="color:rgb(0,134,179)">true</span>
}
<span style="color:rgb(167,29,93)">class</span> Subclass: Base {
<span style="color:rgb(167,29,93)">static</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">eq</span>(lhs: Subclass, <span style="color:rgb(121,93,163)">_</span> <span>rhs</span>: Subclass) <span style="color:rgb(167,29,93)">-></span> <span style="color:rgb(0,134,179)">Bool</span> {
<span style="color:rgb(0,134,179)">print</span>(<span style="color:rgb(24,54,145)"><span>"</span>Subclass.eq(Subclass, Subclass)<span>"</span></span>)
<span style="color:rgb(167,29,93)">return</span> <span style="color:rgb(0,134,179)">true</span>
}
}
<span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">==</span>(lhs: Subclass, rhs: Subclass) <span style="color:rgb(167,29,93)">-></span> <span style="color:rgb(0,134,179)">Bool</span> {
<span style="color:rgb(0,134,179)">print</span>(<span style="color:rgb(24,54,145)"><span>"</span>==(Subclass, Subclass)<span>"</span></span>)
<span style="color:rgb(167,29,93)">return</span> <span style="color:rgb(0,134,179)">true</span>
}
<span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">eq</span><T: ProposedEquatable>(lhs: T, <span style="color:rgb(121,93,163)">_</span> <span>rhs</span>: T) <span style="color:rgb(167,29,93)">-></span> <span style="color:rgb(0,134,179)">Bool</span> {
<span style="color:rgb(167,29,93)">return</span> T<span style="color:rgb(167,29,93)">.</span>eq(lhs, rhs)
}
<span style="color:rgb(167,29,93)">let</span> x <span style="color:rgb(167,29,93)">=</span> Subclass()
<span style="color:rgb(167,29,93)">let</span> y <span style="color:rgb(167,29,93)">=</span> Subclass()
<span style="color:rgb(167,29,93)">let</span> z <span style="color:rgb(167,29,93)">=</span> y <span style="color:rgb(167,29,93)">as</span> Base
eq(x, y) <span style="color:rgb(150,152,150)">// prints "Base.eq"</span>
eq(x, z) <span style="color:rgb(150,152,150)">// prints "Base.eq"</span>
x <span style="color:rgb(167,29,93)">==</span> y <span style="color:rgb(150,152,150)">// prints "==(Subclass, Subclass)"</span>
x <span style="color:rgb(167,29,93)">==</span> z <span style="color:rgb(150,152,150)">// prints "==(Base, Base)"</span></pre></div><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">The result of <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">eq(x, y)</code> was a bit surprising, since the generic argument <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">T</code> is bound to <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Subclass</code> and there should be no dynamic dispatch at play there. (Is the issue that since <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Base</code> is the class explicitly conforming to <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">ProposedEquatable</code>, this is locking in <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Self</code> being bound as <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Base</code>, causing that overload to be found in the compiler's search? Or is this a bug?)</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">An attempt was also made to fix this using dynamic dispatch, by implementing <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">eq</code> as a <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">class</code> method instead of a<code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">static</code> method:</p><div style="margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;margin-top:0px;margin-bottom:0px;font-stretch:normal;line-height:1.45;padding:16px;overflow:auto;border-radius:3px;word-wrap:normal;word-break:normal;background-color:rgb(247,247,247)"><span style="color:rgb(167,29,93)">protocol</span> ProposedEquatable {
<span style="color:rgb(167,29,93)">static</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">eq</span>(lhs: <span style="color:rgb(167,29,93)">Self</span>, <span style="color:rgb(121,93,163)">_</span> <span>rhs</span>: <span style="color:rgb(167,29,93)">Self</span>) <span style="color:rgb(167,29,93)">-></span> <span style="color:rgb(0,134,179)">Bool</span>
}
<span style="color:rgb(167,29,93)">class</span> Base: ProposedEquatable, <span style="color:rgb(0,134,179)">Equatable</span> {
<span style="color:rgb(167,29,93)">class</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">eq</span>(lhs: Base, <span style="color:rgb(121,93,163)">_</span> <span>rhs</span>: Base) <span style="color:rgb(167,29,93)">-></span> <span style="color:rgb(0,134,179)">Bool</span> {
<span style="color:rgb(0,134,179)">print</span>(<span style="color:rgb(24,54,145)"><span>"</span>Base.eq<span>"</span></span>)
<span style="color:rgb(167,29,93)">return</span> <span style="color:rgb(0,134,179)">true</span>
}
}
<span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">==</span>(lhs: Base, rhs: Base) <span style="color:rgb(167,29,93)">-></span> <span style="color:rgb(0,134,179)">Bool</span> {
<span style="color:rgb(0,134,179)">print</span>(<span style="color:rgb(24,54,145)"><span>"</span>==(Base, Base)<span>"</span></span>)
<span style="color:rgb(167,29,93)">return</span> <span style="color:rgb(0,134,179)">true</span>
}
<span style="color:rgb(167,29,93)">class</span> Subclass: Base {
<span style="color:rgb(167,29,93)">override</span> <span style="color:rgb(167,29,93)">class</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">eq</span>(lhs: Base, <span style="color:rgb(121,93,163)">_</span> <span>rhs</span>: Base) <span style="color:rgb(167,29,93)">-></span> <span style="color:rgb(0,134,179)">Bool</span> {
<span style="color:rgb(0,134,179)">print</span>(<span style="color:rgb(24,54,145)"><span>"</span>Subclass.eq(Base, Base)<span>"</span></span>)
<span style="color:rgb(167,29,93)">return</span> <span style="color:rgb(0,134,179)">true</span>
}
<span style="color:rgb(167,29,93)">class</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">eq</span>(lhs: Subclass, <span style="color:rgb(121,93,163)">_</span> <span>rhs</span>: Subclass) <span style="color:rgb(167,29,93)">-></span> <span style="color:rgb(0,134,179)">Bool</span> {
<span style="color:rgb(0,134,179)">print</span>(<span style="color:rgb(24,54,145)"><span>"</span>Subclass.eq(Subclass, Subclass)<span>"</span></span>)
<span style="color:rgb(167,29,93)">return</span> <span style="color:rgb(0,134,179)">true</span>
}
}
<span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">==</span>(lhs: Subclass, rhs: Subclass) <span style="color:rgb(167,29,93)">-></span> <span style="color:rgb(0,134,179)">Bool</span> {
<span style="color:rgb(0,134,179)">print</span>(<span style="color:rgb(24,54,145)"><span>"</span>==(Subclass, Subclass)<span>"</span></span>)
<span style="color:rgb(167,29,93)">return</span> <span style="color:rgb(0,134,179)">true</span>
}
<span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">eq</span><T: ProposedEquatable>(lhs: T, <span style="color:rgb(121,93,163)">_</span> <span>rhs</span>: T) <span style="color:rgb(167,29,93)">-></span> <span style="color:rgb(0,134,179)">Bool</span> {
<span style="color:rgb(167,29,93)">return</span> T<span style="color:rgb(167,29,93)">.</span>eq(lhs, rhs)
}
<span style="color:rgb(167,29,93)">let</span> x <span style="color:rgb(167,29,93)">=</span> Subclass()
<span style="color:rgb(167,29,93)">let</span> y <span style="color:rgb(167,29,93)">=</span> Subclass()
<span style="color:rgb(167,29,93)">let</span> z <span style="color:rgb(167,29,93)">=</span> y <span style="color:rgb(167,29,93)">as</span> Base
eq(x, y) <span style="color:rgb(150,152,150)">// prints "Subclass.eq(Base, Base)"</span>
eq(x, z) <span style="color:rgb(150,152,150)">// prints "Base.eq"</span>
x <span style="color:rgb(167,29,93)">==</span> y <span style="color:rgb(150,152,150)">// prints "==(Subclass, Subclass)"</span>
x <span style="color:rgb(167,29,93)">==</span> z <span style="color:rgb(150,152,150)">// prints "==(Base, Base)"</span></pre></div><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">This helped slightly, since at least it resulting in a method on the expected subclass being called, but this still means that anyone implementing this operator on subclasses would have to do some casting, and it's awkward that subclasses would be expected to write its operator in terms of the conforming base class.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">It should also be noted (code not provided here) that using instance methods does not solve this problem, presumably for the same dispatch-related reasons that the class methods called the version with <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Base</code> arguments.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">However, the lack of multiple dispatch in Swift means that the operators we have today don't necessarily work the way a user would expect (for example, the <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">x == z</code> expression above), so it's debatable whether this is a significant concern.</p><h3 style="margin-top:1em;margin-bottom:16px;line-height:1.43;font-size:1.5em;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol'"><a href="https://github.com/allevato/swift-evolution/blob/master/proposals/0000-improving-operators-in-protocols.md#stretch-goal-automatically-generating-trampolines" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1.2;background-color:transparent" target="_blank"></a>Stretch goal: Automatically generating trampolines</h3><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">To further ease the use of protocol-defined operators, the compiler could automatically define the trampoline operator function at global scope. For example, a protocol and operator of the form</p><div style="margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;margin-top:0px;margin-bottom:0px;font-stretch:normal;line-height:1.45;padding:16px;overflow:auto;border-radius:3px;word-wrap:normal;word-break:normal;background-color:rgb(247,247,247)"><span style="color:rgb(167,29,93)">protocol</span> SomethingAddable {
<span style="color:rgb(167,29,93)">static</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">+</span>(lhs: <span style="color:rgb(167,29,93)">Self</span>, rhs: <span style="color:rgb(167,29,93)">Self</span>) <span style="color:rgb(167,29,93)">-></span> Self
}</pre></div><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">could automatically produce a generic global trampoline operator constrained by the protocol type (by substituting for<code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Self</code>), with the same visibility as the protocol. The body of this would simply delegate to the static/class operator of the concrete type:</p><div style="margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;margin-top:0px;margin-bottom:0px;font-stretch:normal;line-height:1.45;padding:16px;overflow:auto;border-radius:3px;word-wrap:normal;word-break:normal;background-color:rgb(247,247,247)"><span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">+</span> <τ_0: SomethingAddable>(lhs: τ_0, rhs: τ_0) <span style="color:rgb(167,29,93)">-></span> τ_0 {
<span style="color:rgb(167,29,93)">return</span> τ_0<span style="color:rgb(167,29,93)">.+</span>(lhs, rhs)
}</pre></div><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">This approach could be extended for heterogeneous parameter lists:</p><div style="margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;margin-top:0px;margin-bottom:0px;font-stretch:normal;line-height:1.45;padding:16px;overflow:auto;border-radius:3px;word-wrap:normal;word-break:normal;background-color:rgb(247,247,247)"><span style="color:rgb(167,29,93)">protocol</span> IntegerAddable {
<span style="color:rgb(167,29,93)">static</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">+</span>(lhs: <span style="color:rgb(167,29,93)">Self</span>, rhs: <span style="color:rgb(0,134,179)">Int</span>) <span style="color:rgb(167,29,93)">-></span> Self
}
<span style="color:rgb(150,152,150)">// Auto-generated by the compiler</span>
<span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">+</span> <τ_0: IntegerAddable>(lhs: τ_0, rhs: <span style="color:rgb(0,134,179)">Int</span>) <span style="color:rgb(167,29,93)">-></span> τ_0 {
<span style="color:rgb(167,29,93)">return</span> τ_0<span style="color:rgb(167,29,93)">.+</span>(lhs, rhs)
}</pre></div><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">Additional generic constraints could even be propagated to the trampoline operator:</p><div style="margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;margin-top:0px;margin-bottom:0px;font-stretch:normal;line-height:1.45;padding:16px;overflow:auto;border-radius:3px;word-wrap:normal;word-break:normal;background-color:rgb(247,247,247)"><span style="color:rgb(167,29,93)">protocol</span> GenericAddable {
<span style="color:rgb(167,29,93)">static</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">+</span> <Arg: AnotherProtocol>(lhs: <span style="color:rgb(167,29,93)">Self</span>, rhs: Arg) <span style="color:rgb(167,29,93)">-></span> Self
}
<span style="color:rgb(150,152,150)">// Auto-generated by the compiler</span>
<span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">+</span> <τ_0: GenericAddable, τ_1: AnotherProtocol>(lhs: τ_0, rhs: τ_1) <span style="color:rgb(167,29,93)">-></span> τ_0 {
<span style="color:rgb(167,29,93)">return</span> τ_0<span style="color:rgb(167,29,93)">.+</span>(lhs, rhs)
}</pre></div><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">One major benefit of this is that neither the protocol author nor developers writing types conforming to that protocol would have to write <em>any</em> code that lives outside the protocol. This feels clean and consistent.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">This feature, however, may be more controversial, because:</p><ul style="padding-left:2em;margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px"><li>It involves the compiler implicitly generating glue code behind the scenes, which is less discoverable and may be considered "magic".</li><li>It raises the question of whether users should be allowed to define their own trampolines that match the signatures of the auto-generated ones, and if so, how the conflict is resolved.</li><li>Defining the trampoline operator manually requires a trivial amount of effort, and that effort is a one-time exercise by the protocol author.</li></ul><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">In addition, automatic trampoline generation is a much deeper change that would likely not be implementable in the Swift 3 timeline, so we will defer this for a future proposal and deeper discussion later.</p><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol'"><a href="https://github.com/allevato/swift-evolution/blob/master/proposals/0000-improving-operators-in-protocols.md#detailed-design" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1;background-color:transparent" target="_blank"></a>Detailed design</h2><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">Currently, the Swift language allows the use of operators as the names of global functions and of functions in protocols. This proposal is essentially asking to extend that list to include static/class methods of protocols and concrete types and to support referencing them in expressions using the <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">.</code> operator.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">Interestingly, the production rules themselves of the Swift grammar for function declarations <em>already</em> appear to support declaring static functions inside a protocol or other type with names that are operators. In fact, declaring a static operator function in a protocol works today (that is, the static modifier is ignored).</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">However, defining such a function in a concrete type fails with the error <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">operators are only allowed at global scope</code>.<a href="https://github.com/apple/swift/blob/797260939e1f9e453ab49a5cc6e0a7b40be61ec9/lib/Parse/ParseDecl.cpp#L4444" style="color:rgb(64,120,192);text-decoration:none;background-color:transparent" target="_blank">This area</a> of <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Parser::parseDeclFunc</code> appears to be the likely place to make a change to allow this.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">In order to support <em>calling</em> a static operator using its name, the production rules for <em>explicit-member-expression</em> would need to be updated to support operators where they currently only support identifiers:</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px"><em>explicit-member-expression</em> → <em>postfix-expression</em> <span style="font-weight:bolder">.</span> <em>identifier</em> <em>generic-argument-clause</em><span style="font-size:12px;line-height:0;vertical-align:baseline"><em>opt</em></span><br><em>explicit-member-expression</em> → <em>postfix-expression</em> <span style="font-weight:bolder">.</span> <em>operator</em> <em>generic-argument-clause</em><span style="font-size:12px;line-height:0;vertical-align:baseline"><em>opt</em></span><br><em>explicit-member-expression</em> → <em>postfix-expression</em> <span style="font-weight:bolder">.</span> <em>identifier</em> <span style="font-weight:bolder">(</span> <em>argument-names</em> <span style="font-weight:bolder">)</span><br><em>explicit-member-expression</em> → <em>postfix-expression</em> <span style="font-weight:bolder">.</span> <em>operator</em> <span style="font-weight:bolder">(</span> <em>argument-names</em> <span style="font-weight:bolder">)</span><br></p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">For consistency with other static members, we could consider modifying <em>implicit-member-expression</em> as well, but referring to an operator function with only a dot preceding it might look awkward:</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px"><em>implicit-member-expression</em> → <span style="font-weight:bolder">.</span> <em>identifier</em><br><em>implicit-member-expression</em> → <span style="font-weight:bolder">.</span> <em>operator</em></p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px"><span style="font-weight:bolder">Open question:</span> Are there any potential ambiguities between the dot in the member expression and dots in operators?</p><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol'"><a href="https://github.com/allevato/swift-evolution/blob/master/proposals/0000-improving-operators-in-protocols.md#impact-on-existing-code" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1;background-color:transparent" target="_blank"></a>Impact on existing code</h2><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">The ability to declare operators as static/class functions inside a type is a new feature and would not affect existing code. Likewise, the ability to explicitly reference the operator function of a type (e.g., <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Int.+</code> or <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Int.+(5, 7)</code> would not affect existing code.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">Changing the way operators are declared in protocols (static instead of non-static) would be a breaking change. However, since the syntax forms are mutually exclusive, we may wish to let them coëxist for the time being. That is, protocols that declare non-static operators would have them satisfied by global functions, and protocols that declare static operators would have them satisfied by static methods. While this provides two ways for developers to do the same thing, reducing breakage is a greater goal. We can consider deprecating non-static operators in protocols to lead developers to the new syntax and then remove it in a later version of Swift.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">Applying this change to the protocols already in the Swift standard library (such as <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Equatable</code>) would be a breaking change, because it would change the way by which subtypes conform to that protocol. It might be possible to implement a quick fix that hoists a global operator function into the subtype's definition, either by making it static and moving the code itself or by wrapping it in an extension.</p><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol'"><a href="https://github.com/allevato/swift-evolution/blob/master/proposals/0000-improving-operators-in-protocols.md#alternatives-considered" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1;background-color:transparent" target="_blank"></a>Alternatives considered</h2><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">One alternative would be to do nothing. This would leave us with the problems cited above:</p><ul style="padding-left:2em;margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px"><li>Concrete types either provide their own global operator overloads, increasing the workload of the type checker...</li><li>...<em>or</em> they define generic operators that delegate to named methods, but those named methods bloat the public interface of the type.</li><li>Furthermore, there is no consistency required for these named methods among different types; each can define its own, and subtle differences in naming can lead to user confusion.</li></ul><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">Another alternative would be that instead of using static methods, operators could be defined as instance methods on a type. For example,</p><div style="margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;margin-top:0px;margin-bottom:0px;font-stretch:normal;line-height:1.45;padding:16px;overflow:auto;border-radius:3px;word-wrap:normal;word-break:normal;background-color:rgb(247,247,247)"><span style="color:rgb(167,29,93)">protocol</span> SomeProtocol {
<span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">+</span>(rhs: <span style="color:rgb(167,29,93)">Self</span>) <span style="color:rgb(167,29,93)">-></span> Self
}
<span style="color:rgb(167,29,93)">struct</span> SomeType: SomeProtocol {
<span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">+</span>(rhs: SomeType) <span style="color:rgb(167,29,93)">-></span> SomeType { <span style="color:rgb(167,29,93)">...</span> }
}
<span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">+</span> <T: SomeProtocol>(lhs: T, rhs: T) <span style="color:rgb(167,29,93)">-></span> T {
<span style="color:rgb(167,29,93)">return</span> lhs<span style="color:rgb(167,29,93)">.+</span>(rhs)
}</pre></div><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">There is not much to be gained by doing this, however. It does not solve the dynamic dispatch problem for classes described above, and it would require writing operator method signatures that differ from those of the global operators because the first argument instead becomes the implicit <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">self</code>. As a matter of style, when it doesn't necessarily seem appropriate to elevate one argument of an infix operator—especially one that is commutative—to the special status of "receiver" while the other remains an argument.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">Likewise, commutative operators with heterogeneous arguments are more awkward to implement if operators are instance methods. Consider a contrived example of a <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">CustomStringProtocol</code> type that supports concatenation with <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Character</code>using the <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">+</code> operator, commutatively. With static operators and generic trampolines, both versions of the operator are declared in <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">CustomStringProtocol</code>, as one would expect:</p><div style="margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;margin-top:0px;margin-bottom:0px;font-stretch:normal;line-height:1.45;padding:16px;overflow:auto;border-radius:3px;word-wrap:normal;word-break:normal;background-color:rgb(247,247,247)"><span style="color:rgb(167,29,93)">protocol</span> CustomStringProtocol {
<span style="color:rgb(167,29,93)">static</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">+</span>(lhs: <span style="color:rgb(167,29,93)">Self</span>, rhs: <span style="color:rgb(0,134,179)">Character</span>) <span style="color:rgb(167,29,93)">-></span> Self
<span style="color:rgb(167,29,93)">static</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">+</span>(lhs: <span style="color:rgb(0,134,179)">Character</span>, rhs: <span style="color:rgb(167,29,93)">Self</span>) <span style="color:rgb(167,29,93)">-></span> Self
}
<span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">+</span> <T: CustomStringProtocol>(lhs: T, rhs: <span style="color:rgb(0,134,179)">Character</span>) <span style="color:rgb(167,29,93)">-></span> T {
<span style="color:rgb(167,29,93)">return</span> T<span style="color:rgb(167,29,93)">.+</span>(lhs, rhs)
}
<span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">+</span> <T: CustomStringProtocol>(lhs: <span style="color:rgb(0,134,179)">Character</span>, rhs: T) <span style="color:rgb(167,29,93)">-></span> T {
<span style="color:rgb(167,29,93)">return</span> T<span style="color:rgb(167,29,93)">.+</span>(lhs, rhs)
}</pre></div><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px">Likewise, the implementation of both operators would be contained entirely within the conforming types. If these were instance methods, it's unclear how the version that has the <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Character</code> argument on the left-hand side would be expressed in the protocol, or how it would be implemented if an instance of <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Character</code> were the receiver. Would it be an extension on the <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Character</code> type? This would split the implementation of an operation that logically belongs to <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">CustomStringProtocol</code>across two different locations in the code, which is something we're trying to avoid.</p><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol'"><a href="https://github.com/allevato/swift-evolution/blob/master/proposals/0000-improving-operators-in-protocols.md#acknowledgments" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1;background-color:transparent" target="_blank"></a>Acknowledgments</h2><p style="margin-top:0px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;line-height:25.6px;margin-bottom:0px!important">Thanks to Chris Lattner and Dave Abrahams for contributing to the early discussions, particularly regarding the need to improve type checker performance by genericizing protocol-based operators.</p></div></div>
_______________________________________________<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></div>