<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div><span></span></div><div><br><div class="AppleOriginalContents" style="direction: ltr;"><blockquote type="cite"><div>On Dec 31, 2015, at 3:15 PM, Jesse Rusak <<a href="mailto:me@jesserusak.com">me@jesserusak.com</a>> wrote:</div><br class="Apple-interchange-newline"><div><div>Hi Doug,<br class=""><br class="">I’ve been playing around with an implementation of the warning you referenced here: <a href="https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001584.html">https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001584.html</a><br class=""><br class="">Would it be helpful for me to take this on?</div></div></blockquote><div class="AppleOriginalContents" style="direction: ltr;"><br></div><div class="AppleOriginalContents" style="direction: ltr;">Yes, absolutely!</div><br><blockquote type="cite"><div><div> If so, is there any detail in the radar assigned to you about what exactly should trigger such a warning?</div></div></blockquote><blockquote type="cite"><div><div>For example, I have it currently triggering whenever there’s a method with a matching name, ignoring parameter/return types; it’s not obvious to me how closely they should have to match, if at all, to trigger the warning.</div></div></blockquote><br></div><div class="AppleOriginalContents" style="direction: ltr;">I just realized that I wrote up a big discussion of a related-but-not-identical warning. In either case, there is some kind of radar, and neither gives a lot of detail. </div><div class="AppleOriginalContents" style="direction: ltr;"><br></div><div class="AppleOriginalContents" style="direction: ltr;">In general: just matching on name alone feels like it might produce too many false positives, but exactly matching parameter/return types feels like it might miss cases where this warning would be important, so… I think it’s going to come down to coming up with cases where you do/don’t want to see the warning and tuning the warning to do the right thing. It might be that you want to do some simplistic matching (perhaps akin to what lib/Sema/TypeCheckProtocol.cpp does when inferring type witnesses) that ignores uses of associated types that might have been deduced differently from what the user expected.</div><div class="AppleOriginalContents" style="direction: ltr;"><br></div><div class="AppleOriginalContents" style="direction: ltr;">That leads to my #1 example I’d love to get a warning for, which is when you intended to provide something to satisfy a protocol requirement, but you ended up getting a default implementation:</div><div class="AppleOriginalContents" style="direction: ltr;"><br></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;"><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;">struct MyGenerator {</div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"> mutating func next() -> Int? { return nil }</div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;">}</div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><br></div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;">struct MyCollection : CollectionType {</div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"> typealias Index = Int</div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><br></div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"> var startIndex: Int { return 0 }</div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"> var endIndex: Int { return 10 }</div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><br></div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"> subscript (index: Int) -> Int {</div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"> return index</div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"> }</div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><br></div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"> func generate() -> MyGenerator {</div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"> print("using MyGenerator")</div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"> return MyGenerator()</div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"> }</div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;">}</div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><br></div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;">func foo<C: CollectionType>(c: C) {</div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"> c.generate()</div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;">}</div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><br></div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;">foo(MyCollection())</div></div></blockquote><div class="AppleOriginalContents" style="direction: ltr;"><br></div><div class="AppleOriginalContents" style="direction: ltr;">Note that there is no output from this program, although one would expect to see “using MyGenerator”.</div><div class="AppleOriginalContents" style="direction: ltr;"><br></div><div class="AppleOriginalContents" style="direction: ltr;">The root of the problem is annoying simple (I “forgot” to state that MyGenerator conforms to GeneratorType). The result is that the implied SequenceType conformance gets a default implementation of “generate” from a protocol extension in the standard library (that produces default generator for any SequenceType that is also a CollectionType). Our place to warn about this is at the point where we decide to use a “generate” from a protocol extension rather than the “generate” in the same “struct” that declares conformance to CollectionType. Obviously, lots of bonus points if we could say why the generate() in the struct wasn’t picked :)</div><div class="AppleOriginalContents" style="direction: ltr;"><br></div><div class="AppleOriginalContents" style="direction: ltr;">That brings up another point about warnings: it’s useful to have a way to suppress them. Let’s say we got a warning for my example above (huzzah!) but I wanted to silence it. A fairly natural way to do so would be to move the “generate” function I defined into a separate extension, so it’s away from where we state conformance to CollectionType:</div><div class="AppleOriginalContents" style="direction: ltr;"><br></div><div class="AppleOriginalContents" style="direction: ltr;"><br></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;"><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;">struct MyGenerator {</div></div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"> mutating func next() -> Int? { return nil }</div></div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;">}</div></div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><br></div></div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;">struct MyCollection : CollectionType {</div></div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"> typealias Index = Int</div></div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><br></div></div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"> var startIndex: Int { return 0 }</div></div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"> var endIndex: Int { return 10 }</div></div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><br></div></div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"> subscript (index: Int) -> Int {</div></div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"> return index</div></div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"> }</div></div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;">}</div><div class="AppleOriginalContents" style="direction: ltr;"><br></div><div class="AppleOriginalContents" style="direction: ltr;">extension MyCollection {</div></div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"> func generate() -> MyGenerator { // no warning</div></div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"> print("using MyGenerator")</div></div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"> return MyGenerator()</div></div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"> }</div></div></div><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;"><div class="AppleOriginalContents" style="direction: ltr;">}</div><div class="AppleOriginalContents" style="direction: ltr;"><br></div></div></div></blockquote><div>Effectively, we’re using the declaration of conformance to a protocol as indicating user intent that the contents of this particular definition/extension involve that conformance.</div><div><br></div><div>The actual warning you are talking about is very, very similar, and would likely use most of the same logic. The part that differs is the trigger: whenever one declares something within a type, perform a lookup in that type to determine whether there are any similar members of extensions of one of the protocols that type conforms to. You'll want to think about how to suppress the warning when the user wants to. </div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>- Doug</div><div><br></div></div></body></html>