[swift-evolution] [swift-evolution-announce] [Review] SE-0089: Replace protocol<P1, P2> syntax with Any<P1, P2>
Dave Abrahams
dabrahams at apple.com
Wed Jun 8 17:18:19 CDT 2016
on Wed Jun 08 2016, Austin Zheng <austinzheng-AT-gmail.com> wrote:
> We might be talking past each other. I think Matthew is talking about using
> an existential outside the context of generic functions. For example,
> something like this should be trap-proof (as long as 'x' is immutable,
> which it is in this example):
[Ugh, Austin, your mail program is stripping the tabs out of the
plaintext part so the indendation is lost. Grabbing from browser...]
> func copySequenceIntoArray(x: Any<Sequence where .Iterator.Element == Int>) -> [Int] {
> var buffer : [Int] = []
> // Stupid implementation to make a point
> var iterator : x.Iterator = x.makeIterator()
> while true {
> let nextItem : Int? = iterator.next()
> if let nextItem = nextItem {
> buffer.append(nextItem)
> } else {
> return buffer
> }
> }
> }
Presumably this would “work” as well?
typealias IntSequence = Any<Sequence where .Iterator.Element == Int>
func f(x: IntSequence, y: IntSequence) {
var i = x.makeIterator()
i = y.makeIterator() // <== NO TRAP HERE, EVER.
}
> Even this would never trap as well:
>
> func copySequenceIntoArray<T>(x: Any<Sequence where .Iterator.Element == T>) -> [T] {
> var buffer : [T] = []
> for item in x {
> buffer.append(item)
> }
> return buffer
> }
Sure, this one is simple because the associated type is never even
exposed.
> Where we run into difficulty is something like this (forgive my abuse
> of the collections API; I don't remember all the new indexing APIs off
> the top of my head):
>
> func doSomething<T : Collection where T.Element == Int>(x: T, y: T) {
> // Get indexes out of x and use them to index into y
> var idx = x.startIndex
> while (idx != x.endIndex || idx != y.endIndex) {
> print(x[idx])
> print(y[idx])
> idx = x.nextIndex(idx)
> }
> }
> let someSeq : Any<Collection where .Element == Int> = // ...
> let anotherSeq : Any<Collection where .Element == Int> = // ...
> // Trouble!
> // someSeq and anotherSeq are the same existential type
> // But the concrete index types within each of the existential variables may be different
> doSomething(someSeq, anotherSeq)
>
> may be different
> doSomething(someSeq, anotherSeq)
>
> It's this situation (using an existential type to fulfill a generic
> type parameter constrained to the same requirements that comprise that
> existential) that requires either of the two options that Dave
> presented, due to our lack of compile-time type information about the
> fulfilling type's associated types.
Exactly. But much simpler cases will also either have to trap at
runtime or be prohibited outright:
func subscript_<C: Collection>(c: C, i: C.Index) -> C.Collection.Element {
return c[i]
}
typealias IntCollection = Any<Collection where Element == Int>
let c1: IntCollection = ...
let c2: IntCollection = c1[3..<10]
let c3: IntCollection = ...
let c4: IntCollection = c1.reversed()
// Note: the underlying index types are the same, and are supposed to
// interoperate. What do you do (work/trap/nocompile)?
_ = subscript_(c1, c2.startIndex)
// The underlying index types happen to be the same, and are not
// supposed to interoperate. What do you do (silently “work”/trap/nocompile)?
_ = subscript_(c1, c3.startIndex)
// The underlying index types are different. What do you do (trap/nocompile)?
_ = subscript_(c1, c4.startIndex)
--
Dave
More information about the swift-evolution
mailing list