<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div><blockquote type="cite" class=""><div class="">On Apr 25, 2016, at 10:09 AM, John McCall via swift-dev <<a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><blockquote type="cite" class=""><div class="">On Apr 25, 2016, at 9:57 AM, Douglas Gregor <<a href="mailto:dgregor@apple.com" class="">dgregor@apple.com</a>> wrote:</div><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><blockquote type="cite" class=""><div class="">On Apr 22, 2016, at 6:08 PM, John McCall <<a href="mailto:rjmccall@apple.com" class="">rjmccall@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div 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-stroke-width: 0px;" class=""><blockquote type="cite" class=""><div class="">On Apr 22, 2016, at 3:33 PM, Douglas Gregor via swift-dev <<a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a>> wrote:</div><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;">Hi all,<div class=""><br class=""></div><div class="">A common complaint with protocol conformance checking is that it’s easy to make a little mistake when trying to implement a protocol requirement that has a default implementation. Here is a silly example:</div><div class="">[snip]</div><div class=""><br class=""></div><div class="">Naturally, this handles typos as well, e.g.,</div><div class=""><br class=""></div><div class=""><div class="" style="margin: 0px; font-size: 10px; line-height: normal; font-family: Monaco; color: rgb(255, 255, 255); background-color: rgb(0, 0, 0);"><span class="" style="font-variant-ligatures: no-common-ligatures;">t2.swift:12:8:<span class="Apple-converted-space"> </span></span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(213, 59, 211);">warning:<span class="Apple-converted-space"> </span></span><span class="" style="font-variant-ligatures: no-common-ligatures;">instance method 'foob(value:)' nearly matches optional requirement 'foo(value:)' of protocol 'P'</span></div><div class="" style="margin: 0px; font-size: 10px; line-height: normal; font-family: Monaco; color: rgb(196, 196, 196); background-color: rgb(0, 0, 0);"><span class="" style="font-variant-ligatures: no-common-ligatures;"> func foob(value: Float) { }</span></div><div class="" style="margin: 0px; font-size: 10px; line-height: normal; font-family: Monaco; color: rgb(52, 189, 38); background-color: rgb(0, 0, 0);"><span class="" style="font-variant-ligatures: no-common-ligatures;"> ^</span></div><div class="" style="margin: 0px; font-size: 10px; line-height: normal; font-family: Monaco; color: rgb(255, 255, 255); background-color: rgb(0, 0, 0);"><span class="" style="font-variant-ligatures: no-common-ligatures;">t2.swift:12:8:<span class="Apple-converted-space"> </span></span><span class="">note:<span class="Apple-converted-space"> </span></span><span class="" style="font-variant-ligatures: no-common-ligatures;">rename to 'foo(value:)' to satisfy this requirement</span></div><div class="" style="margin: 0px; font-size: 10px; line-height: normal; font-family: Monaco; color: rgb(196, 196, 196); background-color: rgb(0, 0, 0);"><span class="" style="font-variant-ligatures: no-common-ligatures;"> func foob(value: Float) { }</span></div><div class="" style="margin: 0px; font-size: 10px; line-height: normal; font-family: Monaco; color: rgb(52, 189, 38); background-color: rgb(0, 0, 0);"><span class="" style="font-variant-ligatures: no-common-ligatures;"> ^~~~</span></div><div class="" style="margin: 0px; font-size: 10px; line-height: normal; font-family: Monaco; color: rgb(196, 196, 196); background-color: rgb(0, 0, 0);"><span class="" style="font-variant-ligatures: no-common-ligatures;"> foo</span></div></div><div class=""><span class="" style="font-variant-ligatures: no-common-ligatures;"><br class=""></span></div><div class="">Running this on the standard library produces a number of results:</div><div class=""><br class=""></div><div class=""><div class="" style="margin: 0px; font-size: 10px; line-height: normal; font-family: Monaco; color: rgb(196, 196, 196); background-color: rgb(0, 0, 0);"><span class="" style="font-variant-ligatures: no-common-ligatures;">/Users/dgregor/Projects/swift/swift/stdlib/public/core/Arrays.swift.gyb:726:24: warning: instance method 'removeLast()' nearly matches optional requirement 'removeFirst()' of protocol 'RangeReplaceableCollection'</span></div><div class="" style="margin: 0px; font-size: 10px; line-height: normal; font-family: Monaco; color: rgb(196, 196, 196); background-color: rgb(0, 0, 0);"><span class="" style="font-variant-ligatures: no-common-ligatures;"> public mutating func removeLast() -> Element {</span></div><div class="" style="margin: 0px; font-size: 10px; line-height: normal; font-family: Monaco; color: rgb(196, 196, 196); background-color: rgb(0, 0, 0);"><span class="" style="font-variant-ligatures: no-common-ligatures;"> ^</span></div><div class="" style="margin: 0px; font-size: 10px; line-height: normal; font-family: Monaco; color: rgb(196, 196, 196); background-color: rgb(0, 0, 0);"><span class="" style="font-variant-ligatures: no-common-ligatures;">/Users/dgregor/Projects/swift/swift/stdlib/public/core/Arrays.swift.gyb:726:24: note: rename to 'removeFirst()' to satisfy this requirement</span></div><div class="" style="margin: 0px; font-size: 10px; line-height: normal; font-family: Monaco; color: rgb(196, 196, 196); background-color: rgb(0, 0, 0);"><span class="" style="font-variant-ligatures: no-common-ligatures;"> public mutating func removeLast() -> Element {</span></div><div class="" style="margin: 0px; font-size: 10px; line-height: normal; font-family: Monaco; color: rgb(196, 196, 196); background-color: rgb(0, 0, 0);"><span class="" style="font-variant-ligatures: no-common-ligatures;"> ^~~~~~~~~~</span></div><div class="" style="margin: 0px; font-size: 10px; line-height: normal; font-family: Monaco; color: rgb(196, 196, 196); background-color: rgb(0, 0, 0);"><span class="" style="font-variant-ligatures: no-common-ligatures;"> removeFirst</span></div><div class="" style="margin: 0px; font-size: 10px; line-height: normal; font-family: Monaco; color: rgb(196, 196, 196); background-color: rgb(0, 0, 0);"><span class="" style="font-variant-ligatures: no-common-ligatures;">/Users/dgregor/Projects/swift/swift/stdlib/public/core/Arrays.swift.gyb:726:24: note: move 'removeLast()' to another extension to silence this warning</span></div><div class="" style="margin: 0px; font-size: 10px; line-height: normal; font-family: Monaco; color: rgb(196, 196, 196); background-color: rgb(0, 0, 0);"><span class="" style="font-variant-ligatures: no-common-ligatures;"> public mutating func removeLast() -> Element {</span></div><div class="" style="margin: 0px; font-size: 10px; line-height: normal; font-family: Monaco; color: rgb(196, 196, 196); background-color: rgb(0, 0, 0);"><span class="" style="font-variant-ligatures: no-common-ligatures;"> ^</span></div><div class="" style="margin: 0px; font-size: 10px; line-height: normal; font-family: Monaco; color: rgb(196, 196, 196); background-color: rgb(0, 0, 0);"><span class="" style="font-variant-ligatures: no-common-ligatures;">/Users/dgregor/Projects/swift/swift/stdlib/public/core/RangeReplaceableCollection.swift:158:17: note: requirement 'removeFirst()' declared here</span></div><div class="" style="margin: 0px; font-size: 10px; line-height: normal; font-family: Monaco; color: rgb(196, 196, 196); background-color: rgb(0, 0, 0);"><span class="" style="font-variant-ligatures: no-common-ligatures;"> mutating func removeFirst() -> Iterator.Element</span></div><div class="" style="margin: 0px; font-size: 10px; line-height: normal; font-family: Monaco; color: rgb(196, 196, 196); background-color: rgb(0, 0, 0);"><span class="" style="font-variant-ligatures: no-common-ligatures;"> ^</span></div></div></div></div></blockquote><div class=""><br class=""></div>Would a word-by-word edit-distance heuristic work better? That is, removeFirst is not a plausible typo for removeLast because First is not a plausible typo for Last.</div></div></blockquote><br class=""></div><div class="">A word-by-word edit distance seems to imply that if *any* word is too far off, reject. I’m a bit concerned that it would create false negatives.</div></div></div></blockquote><div class=""><br class=""></div>Any shift in the heuristic will eliminate false positives at the risk of creating false negatives.</div><div class=""><br class=""></div><div class="">A word-by-word heuristic allows you to catch a large number of typos in a long method name without matching completely different words just because the method name is long. That seems like the right trade-off to me.</div></div></div></blockquote><div><br class=""></div><div>Common mistakes may well include omitting a word or inserting an extra word. The resulting cascade of word-by-word mismatches is something I’d expect our algorithm to deal with more gracefully than purely word index-based comparisons could handle.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">One possibility in this space would be to remove common words from consideration. That way, only the mismatching words will be used to do the edit-distance computation, so the one-mistake-per-N-characters-typed heuristic wouldn’t consider the completely-matching parts.</div></div></div></blockquote><div class=""><br class=""></div>I think you have fallen a bit too in love with dictionaries.</div><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">In defense of the warning in this case: RangeReplaceableCollection has a “removeFirst” but not a “removeLast”; the conforming type here is implementing “removeLast” but not “removeFirst”. It is *so easy* to imagine this as programmer error that the warning feels justified.</div></div></div></blockquote><div class=""><br class=""></div></div>This does not feel like it leads to a reasonable general principle. At best it calls for some way to opt in to a warning about implementing only "related" methods, analogous the related-type warnings in ObjC ARC bridging.<div class=""><br class=""></div><div class="">John.</div></div>_______________________________________________<br class="">swift-dev mailing list<br class=""><a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-dev<br class=""></div></blockquote></div><br class=""></body></html>