Type inference failing to solve Collection's associated types in protocol extensions

Hello fellow Swift enthusiasts.

I’m struggling to understand why type inference fails to solve Collection s associated types while trying to provide it with a default implementation, via protocol extensions, when an additional subscript is provided. Here is a minimal example:

protocol SearchTree: Collection {
    subscript(key: Int) -> String? { get }
}

extension SearchTree {
    // MARK: Conformance to Sequence
    func makeIterator() -> AnyIterator<(key: Int, value: String)> {
        return AnyIterator { nil }
    }

    // MARK: Conformance to Collection
    var startIndex: Int { return 0 }
    var endIndex: Int { return 0 }
    func index(after i: Int) -> Int { return 0 }
    subscript(key: Int) -> (key: Int, value: String) { return (0, "") }

    // MARK: Conformance to SearchTree
    subscript(key: Int) -> String? { return nil }
}

struct ConformingTree: SearchTree {
}

Swift’s compiler complains that ConformingTree doesn’t conform to Collection. But it doesn’t say a word if I either remove the additional subscript `(key: Int) -> String?`, or if I push the declaration of the subscript in ConformingTree.

I asked this question on StackOverflow (https://stackoverflow.com/questions/46028205), and was kindly taught that I should specify associated types in the protocol (or in the extension via type aliases) because the type inference was getting confused determining the type of Collection.Element, having to deal with two subscripts. What I still don’t understand is why the type inference doesn’t need such explicit additional information when the implementation of SearchTree’s requirement is placed in the concrete type.

Could anyone enlighten me on this?

Thanks a lot for your time.
Best regards.

Dimitri Racordon
CUI, Université de Genève
7, route de Drize, CH-1227 Carouge - Switzerland
Phone: +41 22 379 01 24

Hi, Dimitri. The Swift compiler always tries to choose the most specific function when it tries to satisfy protocol requirements. In your case, that means it's going to prefer members defined in concrete types over members defined in protocol extensions. Unfortunately I think that means you're not getting the Collection you expect—the "additional" subscript becomes the "more specific" one, and the compiler decides that the collection Element should be 'String?'. As you noted, you can use typealiases to explicitly control that and keep the compiler from having to guess.

Hope that clears things up,
Jordan

···

On Sep 4, 2017, at 03:41, Dimitri Racordon via swift-dev <swift-dev@swift.org> wrote:

Hello fellow Swift enthusiasts.

I’m struggling to understand why type inference fails to solve Collection s associated types while trying to provide it with a default implementation, via protocol extensions, when an additional subscript is provided. Here is a minimal example:

protocol SearchTree: Collection {
    subscript(key: Int) -> String? { get }
}

extension SearchTree {
    // MARK: Conformance to Sequence
    func makeIterator() -> AnyIterator<(key: Int, value: String)> {
        return AnyIterator { nil }
    }

    // MARK: Conformance to Collection
    var startIndex: Int { return 0 }
    var endIndex: Int { return 0 }
    func index(after i: Int) -> Int { return 0 }
    subscript(key: Int) -> (key: Int, value: String) { return (0, "") }

    // MARK: Conformance to SearchTree
    subscript(key: Int) -> String? { return nil }
}

struct ConformingTree: SearchTree {
}

Swift’s compiler complains that ConformingTree doesn’t conform to Collection. But it doesn’t say a word if I either remove the additional subscript `(key: Int) -> String?`, or if I push the declaration of the subscript in ConformingTree.

I asked this question on StackOverflow (https://stackoverflow.com/questions/46028205), and was kindly taught that I should specify associated types in the protocol (or in the extension via type aliases) because the type inference was getting confused determining the type of Collection.Element, having to deal with two subscripts. What I still don’t understand is why the type inference doesn’t need such explicit additional information when the implementation of SearchTree’s requirement is placed in the concrete type.

Could anyone enlighten me on this?

Thanks a lot for your time.
Best regards.

Dimitri Racordon
CUI, Université de Genève
7, route de Drize, CH-1227 Carouge - Switzerland
Phone: +41 22 379 01 24

_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev