<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div><br><br>Sent from my iPhone</div><div><br>On Nov 7, 2016, at 7:07 PM, Mark Lacey <<a href="mailto:mark.lacey@apple.com">mark.lacey@apple.com</a>> wrote:<br><br></div><blockquote type="cite"><div><meta http-equiv="Content-Type" content="text/html charset=utf-8"><br class=""><div><blockquote type="cite" class=""><div class="">On Nov 7, 2016, at 6:16 PM, Douglas Gregor 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="">Hi all,<div class=""><br class=""></div><div class="">While working on the type checker, I came across an interesting case for associated type inference with the ‘Indices’ type of RandomAccessCollection. At issue is a simple model of RandomAccessCollection where the Index type is Int:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Menlo" class="">class ReferenceCollection : RandomAccessCollection {</font></div></div><div class=""><div class=""><font face="Menlo" class=""> typealias Index = Int</font></div></div><div class=""><div class=""><font face="Menlo" class=""> </font></div></div><div class=""><div class=""><font face="Menlo" class=""> var startIndex: Int {</font></div></div><div class=""><div class=""><font face="Menlo" class=""> return 0</font></div></div><div class=""><div class=""><font face="Menlo" class=""> }</font></div></div><div class=""><div class=""><font face="Menlo" class=""><br class=""></font></div></div><div class=""><div class=""><font face="Menlo" class=""> var endIndex: Int {</font></div></div><div class=""><div class=""><font face="Menlo" class=""> return 1</font></div></div><div class=""><div class=""><font face="Menlo" class=""> }</font></div></div><div class=""><div class=""><font face="Menlo" class=""><br class=""></font></div></div><div class=""><div class=""><font face="Menlo" class=""> subscript(index: Int) -> String {</font></div></div><div class=""><div class=""><font face="Menlo" class=""> return ""</font></div></div><div class=""><div class=""><font face="Menlo" class=""> }</font></div></div><div class=""><div class=""><font face="Menlo" class=""><br class=""></font></div></div><div class=""><div class=""><font face="Menlo" class=""> func index(after i: Int) -> Int {</font></div></div><div class=""><div class=""><font face="Menlo" class=""> return 1</font></div></div><div class=""><div class=""><font face="Menlo" class=""> }</font></div></div><div class=""><div class=""><font face="Menlo" class=""><br class=""></font></div></div><div class=""><div class=""><font face="Menlo" class=""> func index(before i: Int) -> Int {</font></div></div><div class=""><div class=""><font face="Menlo" class=""> return 0</font></div></div><div class=""><div class=""><font face="Menlo" class=""> }</font></div></div><div class=""><div class=""><font face="Menlo" class="">}</font></div></div></blockquote><div class=""><br class=""></div><div class="">What’s the inferred associated Indices? The RandomAccessIterator protocol has a default:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Menlo" class="">protocol RandomAccessCollection {</font></div><div class=""><div class=""><font face="Menlo" class=""> associatedtype Indices : _RandomAccessIndexable, BidirectionalCollection</font></div></div><div class=""><div class=""><font face="Menlo" class=""> = DefaultRandomAccessIndices<Self></font></div></div><div class=""><font face="Menlo" class=""> var indices: Indices { get }</font></div><div class=""><font face="Menlo" class="">}</font></div></blockquote><div class=""><br class=""></div><div class="">which will kick in if nothing else can be inferred. There is also an implementation for this defaulted case in a protocol extension from which we can infer Indices:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Menlo" class="">extension RandomAccessCollection where Indices == DefaultRandomAccessIndices<Self> {</font></div></div><div class=""><div class=""><font face="Menlo" class=""> public var indices: DefaultRandomAccessIndices<Self> { }</font></div></div><div class=""><div class=""><font face="Menlo" class="">}</font></div></div></blockquote><div class=""><br class=""></div><div class="">Those line up, which is easy, but there is *another* protocol extension of RandomAccessIterator from which we can infer Indices:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Menlo" class="">extension RandomAccessCollection</font></div></div><div class=""><div class=""><font face="Menlo" class="">where Index : Strideable, </font></div></div><div class=""><div class=""><font face="Menlo" class=""> Index.Stride == IndexDistance,</font></div></div><div class=""><div class=""><font face="Menlo" class=""> Indices == CountableRange<Index> {</font></div></div><div class=""><div class=""><font face="Menlo" class=""><br class=""></font></div></div><div class=""><div class=""><font face="Menlo" class=""> public var indices: CountableRange<Index> {</font></div></div><div class=""><div class=""><font face="Menlo" class=""> return startIndex..<endIndex</font></div></div><div class=""><div class=""><font face="Menlo" class=""> }</font></div></div><div class=""><div class=""><font face="Menlo" class="">}</font></div></div></blockquote><div class=""><br class=""></div><div class="">Note that both DefaultRandomAccessIndices<ReferenceCollection> and CountableRange<Int> would be valid inferences for Indices. We have three options:</div><div class=""><br class=""></div><div class="">1) Consider type inference to be ambiguous, because there is no natural ordering between the two protocol extensions (they have incompatible same-type constraints on the associated type Indices).</div><div class="">2) Consider the first protocol extension to “win” because… we prefer the extension which corresponds to the associated type default (?). This would be consistent with a world where we don’t have associated type inference at all. (It also matches Swift 3.0.1’s behavior).</div><div class="">3) Consider the second protocol extension to “win” because…the other protocol extension corresponds to the associated type default, and could therefore be considered to be a lowest-common-denominator implementation only there to provide the most basic defaults.</div></div></div></blockquote><div><br class=""></div>I can see the appeal of option 3, but IMO anything other than option 1 seems pretty brittle. Presumably with that option, and with the class providing a typealias for Indices, you would no longer have an ambiguity and the code would compile, correct?</div></div></blockquote><div><br></div>Yes, adding an explicit typealias (to either of them) fixes the issue. <div><br></div><div> - Doug</div><div><br><blockquote type="cite"><div><div>Mark</div><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=""><br class=""></div><div class="">For reference, Swift 3.0.1 picked DefaultRandomAccessIndices<ReferenceCollection>, current Swift master picks CountableRange<Int>, and my work-in-progress to improve the type checker calls it ambiguous, hence the question :)</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>- Doug</div><div class=""><br class=""></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=""><a href="https://lists.swift.org/mailman/listinfo/swift-dev">https://lists.swift.org/mailman/listinfo/swift-dev</a><br class=""></div></blockquote></div><br class=""></div></blockquote></div></body></html>