<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="" applecontenteditable="true"><br class=""><div><blockquote type="cite" class=""><div class="">On Feb 8, 2017, at 11:12 PM, Slava Pestov &lt;<a href="mailto:spestov@apple.com" class="">spestov@apple.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class=""><br class="Apple-interchange-newline">On Feb 8, 2017, at 10:30 PM, Douglas Gregor &lt;<a href="mailto:dgregor@apple.com" class="">dgregor@apple.com</a>&gt; wrote:<br class=""><br class=""><br class=""><blockquote type="cite" class="">On Feb 8, 2017, at 10:21 PM, Slava Pestov &lt;<a href="mailto:spestov@apple.com" class="">spestov@apple.com</a>&gt; wrote:<br class=""><br class="">Hah, Doug and I were just discussing this.<br class=""><br class="">In Swift 3.1, we generalized where clauses to allow them to add requirements on outer generic parameters. However we did not remove the diagnostic prohibiting a where clause from being attached to a non-generic method. In theory this can be made to work; the only slightly tricky thing is we will get a GenericParamList with zero parameters but non-zero requirements, which would require shuffling some things around to avoid assertions.<br class=""><br class="">This would be a good starter project for someone who wanted to learn more about the generics system.<br class=""><br class="">As for index(of:) and the specific details of the stdlib that are involved here, I have no idea — I’m just talking about the bogus diagnostic itself.<br class=""></blockquote><br class="">Well, I think Brent is talking about doing this on a protocol requirement, which is more interesting because not all conforming types would satisfy the requirement…<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Since there would be no way to invoke the requirement on such a type, could we leave the entry blank in the witness table or emit a fatalError() thunk or something?</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""></div></blockquote><div><br class=""></div><div>I’d previously thought so, but retroactive modeling makes this more interesting than that:</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>// Module A</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>public&nbsp;protocol P { }</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>public protocol Q {</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>&nbsp; associatedtype Assoc</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>&nbsp; func f() where Assoc: P</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>public struct X { }</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>public struct Y : Q {</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>&nbsp; public typealias Assoc = X</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>&nbsp; // X doesn’t conform to P, so I guess we can omit f()?</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>public func callF&lt;T: Q&gt;(t: T) where T.Assoc: P {</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>&nbsp; t.f()<span class="Apple-tab-span" style="white-space:pre">        </span>&nbsp;// should be allowed to call f() because we know that T.Assoc conforms to P</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>// Module B</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>public extension X: P { }</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>callF(Y()) // BOOM at runtime, because witness table Y: Q doesn’t include f!</div><div><br class=""></div><div><br class=""></div><div>So, I think that means we can’t just leave a stub there</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>// Back in module A</div><div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>public struct Z : Q {</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>&nbsp; public typealias Assoc = X</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>&nbsp;&nbsp;public&nbsp;func f() where X: P { } &nbsp;// wait, what?</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div class=""><br class=""></div><div class="">That last one is “fun”. The method “f()" is only available when the concrete type X conforms to P. We know it doesn’t right now—but it could in the future. It’s a bit odd to reason about such a function, because you’re evaluating how the concrete type X would behave if it did in fact conform to P! In Swift-compiler-speak, it’s a concrete type with an abstract conformance to P, which is a bit of a model breaker.</div><div class=""><br class=""></div></div><span class="Apple-tab-span" style="white-space:pre">        </span>- Doug</div><div><br class=""><blockquote type="cite" class=""><div class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Slava</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class=""><br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>- Doug<br class=""><br class=""><blockquote type="cite" class=""><br class="">Slava<br class=""><br class=""><blockquote type="cite" class="">On Feb 8, 2017, at 9:57 PM, Brent Royal-Gordon via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:<br class=""><br class="">In an article on `Collection` today*, Ole Begemann points out that `index(of:)`, along with other `Equatable`- and `Comparable`-constrained `Collection` methods, cannot be overridden. Actually, it *can* be, but only through a private mechanism—there's a `_customIndexOfEquatableElement(_:)` method that's invisible in the generated interface. But that only proves the need for a way to make methods like these overridable.<br class=""><br class="">The problem is that the `index(of:)` method should only be offered when the element is `Equatable`—otherwise it simply won't work. But there's no way to specify this rule in current Swift. In theory, we could describe such a requirement with something like this:<br class=""><br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>func index(of element: Iterator.Element) -&gt; Index? where Iterator.Element: Equatable<br class=""><br class="">But this is not permitted—you get an error indicating that `where` clauses are only allowed on generic methods. Adding a spurious generic parameter allows this code to compile, but with a deprecation warning indicating that this is deprecated. I don't know if it would actually behave correctly, however.<br class=""><br class="">Is this a feature we should add? Is this the way to add it? Would it have non-additive ABI impact? (The private `index(of:)` override would certainly go away, but that's why it's private, I suppose.) I don't seem to remember seeing something like this in the generics manifesto, so I thought it was worth bringing up.<br class=""><br class=""><br class=""><br class="">* <a href="https://oleb.net/blog/2017/02/sorted-array/" class="">https://oleb.net/blog/2017/02/sorted-array/</a><br class=""><br class="">--<span class="Apple-converted-space">&nbsp;</span><br class="">Brent Royal-Gordon<br class="">Architechies<br class=""><br class="">_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution</blockquote></blockquote></blockquote></div></blockquote></div><br class=""></body></html>