> Am 09.06.2016 um 00:13 schrieb Matthew Johnson via swift-evolution > <[email protected]>: > > >> On Jun 8, 2016, at 4:47 PM, Austin Zheng <[email protected] >> <mailto:[email protected]>> wrote: >> >> FWIW my opinion is that existentials either shouldn't be allowed to stand in >> for generic type parameters, or Dave's option #1 if they are. >> >> The implied promise of a generic type parameter T right now is that T always >> stands for the same concrete type (modulo things like passing in a subclass >> where a class would do), and likewise for all of T's associated types (T.Foo >> is always the same type everywhere in the context where T is valid). This is >> what makes using anything with 'self' requirements in a generic context >> sound. Allowing existentials to satisfy T would violate that constraint. >> >> Relaxing these semantics would make it too easy to write code that traps at >> runtime "without the user having to reach" (to paraphrase Jordan from the >> "Swift philosophy" thread). Anyone who really really wants to write code >> that is 'compile-time unsound' in this way should have to explicitly type >> erase using concrete wrappers. > > Yes, exactly.
Yup. -Thorsten > >> >> Best, >> Austin >> >> >> On Wed, Jun 8, 2016 at 2:37 PM, Austin Zheng <[email protected] >> <mailto:[email protected]>> 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): >> >> 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 >> } >> } >> } >> >> 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 >> } >> >> 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) >> >> 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. >> >> Best, >> Austin >> >> On Wed, Jun 8, 2016 at 2:33 PM, Matthew Johnson via swift-evolution >> <[email protected] <mailto:[email protected]>> wrote: >> >> >> Sent from my iPad >> >> > On Jun 8, 2016, at 3:16 PM, Dave Abrahams via swift-evolution >> > <[email protected] <mailto:[email protected]>> wrote: >> > >> > >> >> on Wed Jun 08 2016, Thorsten Seitz <[email protected] >> >> <mailto:[email protected]>> wrote: >> >> >> >> Ah, thanks, I forgot! I still consider this a bug, though (will have >> >> to read up again what the reasons are for that behavior). >> > >> > Yes, but in the case of the issue we're discussing, the choices are: >> > >> > 1. Omit from the existential's API any protocol requirements that depend >> > on Self or associated types, in which case it *can't* conform to >> > itself because it doesn't fulfill the requirements. >> >> They don't need to be omitted. They are exposed in different ways depending >> on how the existential is constrained. Austin's proposal was originally >> written to omit some members but it was modified based on feedback from Doug >> Gregor IIRC (Austin, is that right?). Now it contains examples showing how >> these members are made available in a safe way. Some members may still not >> be usable because you can't form an argument but IIRC the suggestion was >> that they be exposed anyway for consistency. >> >> > >> > 2. Erase type relationships and trap at runtime when they don't line up. >> > >> > Matthew has been arguing against #2, but you can't “fix the bug” without >> > it. >> > >> >> >> >> -Thorsten >> >> >> >>> Am 08.06.2016 um 21:43 schrieb Austin Zheng <[email protected] >> >>> <mailto:[email protected]>>: >> >>> >> >>> It's not possible, even with Swift's current implementation of >> >>> existentials. A protocol type P isn't considered to conform to >> >>> itself, thus the following is rejected: >> >>> >> >>> let a : MyProtocol = // ... >> >>> func myFunc<T : MyProtocol>(x: T) { >> >>> // .... >> >>> } >> >>> myFunc(a) // "Cannot invoke 'myFunc' with an argument list of type >> >>> MyProtocol" >> >>> >> >>> Changing how this works is probably worth a proposal by itself. >> >>> >> >>> Austin >> >>> >> >>> >> >>> On Wed, Jun 8, 2016 at 12:34 PM, Thorsten Seitz via swift-evolution >> >>> <[email protected] <mailto:[email protected]> >> >>> <mailto:[email protected] <mailto:[email protected]>>> >> >>> wrote: >> >>> >> >>>> Am 08.06.2016 um 20:33 schrieb Dave Abrahams via swift-evolution >> >>>> <[email protected] <mailto:[email protected]> >> >>>> <mailto:[email protected] <mailto:[email protected]>>>: >> >>>> >> >>>> >> >>>> on Tue Jun 07 2016, Matthew Johnson <matthew-AT-anandabits.com >> >>>> <http://matthew-at-anandabits.com/>> wrote: >> >>>> >> >>>>>> On Jun 7, 2016, at 9:15 PM, Dave Abrahams >> >>>>>> <[email protected] <mailto:[email protected]> >> >>>>>> <mailto:[email protected] <mailto:[email protected]>>> >> >>>>>> wrote: >> >>>>>> >> >>>>>> >> >>>>>> on Tue Jun 07 2016, Matthew Johnson <matthew-AT-anandabits.com >> >>>>>> <http://matthew-at-anandabits.com/> >> >>>>>> <http://matthew-at-anandabits.com/ <http://matthew-at-anandabits.com/> >> >>>>>> <http://matthew-at-anandabits.com/ >> >>>>>> <http://matthew-at-anandabits.com/>>>> wrote: >> >>>>> >> >>>>>>>> On Jun 7, 2016, at 4:13 PM, Dave Abrahams via swift-evolution >> >>>>>>>> <[email protected] <mailto:[email protected]> >> >>>>>>>> <mailto:[email protected] >> >>>>>>>> <mailto:[email protected]>>> >> >>>>>>>> wrote: >> >>>>>>>> >> >>>>>>>> >> >>>>>>>> on Tue Jun 07 2016, Matthew Johnson >> >>>>>>>> <[email protected] <mailto:[email protected]> >> >>>>>>>> <mailto:[email protected] >> >>>>>>>> <mailto:[email protected]>>> >> >>>>>>>> wrote: >> >>>>>>> >> >>>>>>>>>> , but haven't realized >> >>>>>>>>>> that if you step around the type relationships encoded in Self >> >>>>>>>>>> requirements and associated types you end up with types that >> >>>>>>>>>> appear to >> >>>>>>>>>> interoperate but in fact trap at runtime unless used in exactly >> >>>>>>>>>> the >> >>>>>>>>>> right way. >> >>>>>>>>> >> >>>>>>>>> Trap at runtime? How so? Generalized existentials should still be >> >>>>>>>>> type-safe. >> >>>>>>>> >> >>>>>>>> There are two choices when you erase static type relationships: >> >>>>>>>> >> >>>>>>>> 1. Acheive type-safety by trapping at runtime >> >>>>>>>> >> >>>>>>>> FloatingPoint(3.0 as Float) + FloatingPoint(3.0 as Double) // trap >> >>>>>>>> >> >>>>>>>> 2. Don't expose protocol requirements that involve these >> >>>>>>>> relationships, >> >>>>>>>> which would prevent the code above from compiling and prevent >> >>>>>>>> FloatingPoint from conforming to itself. >> >>>>>>>> >> >>>>>>>>> Or are you talking about the hypothetical types / behaviors people >> >>>>>>>>> think they want when they don’t fully understand what is >> >>>>>>>>> happening... >> >>>>>>>> >> >>>>>>>> I don't know what you mean here. I think generalized existentials >> >>>>>>>> will >> >>>>>>>> be nice to have, but I think most people will want them to do >> >>>>>>>> something >> >>>>>>>> they can't possibly do. >> >>>>>>> >> >>>>>>> Exactly. What I meant is that people think they want that expression >> >>>>>>> to compile because they don’t understand that the only thing it can >> >>>>>>> do >> >>>>>>> is trap. I said “hypothetical” because producing a compile time >> >>>>>>> error >> >>>>>>> rather than a runtime trap is the only sane thing to do. Your >> >>>>>>> comment >> >>>>>>> surprised me because I can’t imagine we would move forward in Swift >> >>>>>>> with the approach of trapping. >> >>>>>> >> >>>>>> I would very much like to be able to create instances of “Collection >> >>>>>> where Element == Int” so we can throw away the wrappers in the stdlib. >> >>>>>> That will require some type mismatches to be caught at runtime via >> >>>>>> trapping. >> >>>>> >> >>>>> For invalid index because the existential accepts a type erased index? >> >>>> >> >>>> Exactly. >> >>>> >> >>>>> How do you decide where to draw the line here? It feels like a very >> >>>>> slippery slope for a language where safety is a stated priority to >> >>>>> start adopting a strategy of runtime trapping for something as >> >>>>> fundamental as how you expose members on an existential. >> >>>> >> >>>> If you don't do this, the alternative is that “Collection where Element >> >>>> == Int” does not conform to Collection. That's weird and not very >> >>>> useful. You could expose all the methods that were on protocol >> >>>> extensions of Collection on this existential, unless they used >> >>>> associated types other than the element type. But you couldn't pass the >> >>>> existential to a generic function like >> >>>> >> >>>> func scrambled<C: Collection>(_ c: C) -> [C.Element] >> >>> >> >>> I don’t understand. Why couldn’t an existential be passed to that >> >>> function? >> >>> >> >>> -Thorsten >> >>> >> >>> >> >>> >> >>>> >> >>>>> IMO you should *have* to introduce unsafe behavior like that manually. >> >>>> >> >>>> Collection where Element == Int & Index == * >> >>>> >> >>>> ? >> >>>> >> >>>>> Collection indices are already something that isn’t fully statically >> >>>>> safe so I understand why you might want to allow this. >> >>>> >> >>>> By the same measure, so are Ints :-) >> >>>> >> >>>> The fact that a type's methods have preconditions does *not* make it >> >>>> “statically unsafe.” >> >>>> >> >>>>> But I don’t think having the language's existentials do this >> >>>>> automatically is the right approach. Maybe there is another approach >> >>>>> that could be used in targeted use cases where the less safe behavior >> >>>>> makes sense and is carefully designed. >> >>>> >> >>>> Whether it makes sense or not really depends on the use-cases. There's >> >>>> little point in generalizing existentials if the result isn't very >> >>>> useful. >> >>>> The way to find out is to take a look at the examples we currently have >> >>>> of protocols with associated types or Self requirements and consider >> >>>> what you'd be able to do with their existentials if type relationships >> >>>> couldn't be erased. >> >>>> >> >>>> We have known use-cases, currently emulated in the standard library, for >> >>>> existentials with erased type relationships. *If* these represent the >> >>>> predominant use cases for something like generalized existentials, it >> >>>> seems to me that the language feature should support that. Note: I have >> >>>> not seen anyone build an emulation of the other kind of generalized >> >>>> existential. My theory: there's a good reason for that :-). >> >>>> >> >>>> -- >> >>>> Dave >> >>>> _______________________________________________ >> >>>> swift-evolution mailing list >> >>>> [email protected] <mailto:[email protected]> >> >>>> <mailto:[email protected] <mailto:[email protected]>> >> >>>> https://lists.swift.org/mailman/listinfo/swift-evolution >> >>>> <https://lists.swift.org/mailman/listinfo/swift-evolution> >> >>>> <https://lists.swift.org/mailman/listinfo/swift-evolution >> >>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>> >> >>> >> >>> _______________________________________________ >> >>> swift-evolution mailing list >> >>> [email protected] <mailto:[email protected]> >> >>> <mailto:[email protected] <mailto:[email protected]>> >> >>> https://lists.swift.org/mailman/listinfo/swift-evolution >> >>> <https://lists.swift.org/mailman/listinfo/swift-evolution> >> >>> <https://lists.swift.org/mailman/listinfo/swift-evolution >> >>> <https://lists.swift.org/mailman/listinfo/swift-evolution>> >> >> >> >> _______________________________________________ >> >> swift-evolution mailing list >> >> [email protected] <mailto:[email protected]> >> >> https://lists.swift.org/mailman/listinfo/swift-evolution >> >> <https://lists.swift.org/mailman/listinfo/swift-evolution> >> > >> > -- >> > Dave >> > >> > _______________________________________________ >> > swift-evolution mailing list >> > [email protected] <mailto:[email protected]> >> > https://lists.swift.org/mailman/listinfo/swift-evolution >> > <https://lists.swift.org/mailman/listinfo/swift-evolution> >> >> _______________________________________________ >> swift-evolution mailing list >> [email protected] <mailto:[email protected]> >> https://lists.swift.org/mailman/listinfo/swift-evolution >> <https://lists.swift.org/mailman/listinfo/swift-evolution> >> >> > > _______________________________________________ > swift-evolution mailing list > [email protected] > https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
