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
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to