Removed Inference but code is seemingly still ambiguous

Xcode Version 8.0 (8A218a); Playground; Swift 3;


sample1: initial code

func fooA<C: Collection>(_ x: C)
    where C.Iterator.Element == UInt8, C.IndexDistance == Int
{
    let a = x.prefix(10).first(where: {$0 == 0xbf})
    //        ^^^^ ##ERROR##: Ambiguous reference to member `prefix`
    print(a)
}


sample2: A few iterations later, trying to break expressions into simpler calls and removed inference.

func fooD<C: Collection>(_ x: C)
    where C.Iterator.Element == UInt8, C.IndexDistance == Int
{
    let x2: C.SubSequence = x.prefix(10)
    let z: UInt8 = 0xbf
    let a: UInt8? = x2.first(where: {
        // ##ERROR##: Cannot convert value of type `(UInt8) -> Bool` to expected argument type `(_) -> Bool`
        (a1: UInt8) -> Bool in
        return a1 == z
    })
    print(a)
}



I don't understand where's the ambiguity in "sample2". I would greatly appreciate if someone could indicate where my failings. Thank you!

Accepted Reply

Add the requirement

C.SubSequence.Iterator.Element == UInt8
:

Yeah, that’s a fun gotcha: the elements of a subsequence don’t necessarily have to be of the same type as that of the parent sequence. In situations like this I usually add the

C.Iterator.Element == C.SubSequence.Iterator.Element
requirement.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Replies

Add the requirement C.SubSequence.Iterator.Element == UInt8:


func fooD<C: Collection>(_ x: C)
    where C.IndexDistance == Int, C.SubSequence.Iterator.Element == UInt8

Add the requirement

C.SubSequence.Iterator.Element == UInt8
:

Yeah, that’s a fun gotcha: the elements of a subsequence don’t necessarily have to be of the same type as that of the parent sequence. In situations like this I usually add the

C.Iterator.Element == C.SubSequence.Iterator.Element
requirement.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Yes, I added that first, but then I figured it was easier to just change the requirement. This is bound to pop up now and then, so it should probably be a documented best practice somewhere. Which brings us to the question: what is the proper forum for best practices? The swift-evolution process doesn't seem to fit, or does it?

Which brings us to the question: what is the proper forum for best practices?

To discuss best practices? Or to document them?

To discuss them, I’d go with swift-users, which hosts a wide range of opinions.

To document them, I recommend Radar or the Swift bug tracking system, depending on what document you want the best practices to show up in.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Interesting!


Out of curiosity (and a bit of discussion), is there a known usecase where that — having a subsequence with different element type — would be needed?


Not that having the potential is bad… Just asking to see if there's something I'm overlooking and could learn… Much like with cases where Sequence != SubSequence taught me about Slices.

Out of curiosity (and a bit of discussion), is there a known usecase where … having a subsequence with different element type … would be needed?

I think that we expect

Sequence
and
SubSequence
to always have the same element types but the Swift language can’t express that in the definition of those types and thus you have to do it yourself. This is based on my reading of the Generics Manifesto, and specifically this quote:

Currently, a new protocol can inherit from other protocols, introduce new associated types, and add new conformance constraints to associated types (by redeclaring an associated type from an inherited protocol). However, one cannot express more general constraints. Building on the example from "Recursive protocol constraints", we really want the element type of a Sequence's SubSequence to be the same as the element type of the Sequence

If you want to go deeper into this I (again) recommend swift-users because we’re really butting up against the limits of my understanding of this stuff.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

SE-0142:

Currently, associated type declarations can only express simple inheritance constraints and not the more sophisticated constraints available to generic types with the `where` clause. Some designs, including many in the Standard Library, require more powerful constraints for associated types to be truly elegant. For example, the `SequenceType` protocol could be declared as follows if the current proposal was accepted:
protocol Sequence {
    associatedtype Iterator : IteratorProtocol
    associatedtype SubSequence : Sequence where SubSequence.Iterator.Element == Iterator.Element
    ...
}


This proposal has been accepted for Swift 4.