> On Mar 16, 2017, at 10:23 AM, Joe Groff via swift-evolution 
> <[email protected]> wrote:
> 
> 
>> On Mar 16, 2017, at 10:21 AM, Itai Ferber <[email protected]> wrote:
>> 
>> On 15 Mar 2017, at 19:12, Joe Groff wrote:
>> 
>> 
>> On Mar 15, 2017, at 6:46 PM, Itai Ferber <[email protected]> wrote:
>> 
>> Thanks Joe, and thanks for passing this along!
>> 
>> To those who are curious, we use abstract base classes for a cascading list 
>> of reasons:
>> 
>> • We need to be able to represent keyed encoding and decoding containers as 
>> abstract types which are generic on a key type
>> • There are two ways to support abstraction in this way: protocol & type 
>> constraints, and generic types
>> • Since Swift protocols are not generic, we unfortunately cannot write 
>> protocol KeyedEncodingContainer<Key : CodingKey> { ... }, which is the 
>> "ideal" version of what we're trying to represent
>> • Let's try this with a protocol first (simplified here):
>> 
>> protocol Container {
>> associatedtype Key : CodingKey
>> }
>> 
>> func container<Key : CodingKey, Cont : Container>(_ type: Key.Type) -> Cont 
>> where Cont.Key == Key {
>> // return something
>> }
>> 
>> This looks promising so far — let's try to make it concrete:
>> 
>> struct ConcreteContainer<K : CodingKey> : Container {
>> typealias Key = K
>> }
>> 
>> func container<Key : CodingKey, Cont : Container>(_ type: Key.Type) -> Cont 
>> where Cont.Key == Key {
>> return ConcreteContainer<Key>() // error: Cannot convert return expression 
>> of type 'ConcreteContainer<Key>' to return type 'Cont'
>> }
>> 
>> Joe or anyone from the Swift team can describe this better, but this is my 
>> poor-man's explanation of why this happens. Swift's type constraints are 
>> "directional" in a sense. You can constrain a type going into a function, 
>> but not out of a function. There is no type I could return from inside of 
>> container() which would satisfy this constraint, because the constraint can 
>> only be satisfied by turning Cont into a concrete type from the outside.
>> 
>> Okay, well let's try this:
>> 
>> func container... {
>> return ConcreteContainer<Key>() as! Cont
>> }
>> 
>> This compiles fine! Hmm, let's try to use it:
>> 
>> container(Int.self) // error: Generic parameter 'Cont' could not be inferred
>> 
>> The type constraint can only be fulfilled from the outside, not the inside. 
>> The function call itself has no context for the concrete type that this 
>> would return, so this is a no-go.
>> 
>> • If we can't do it with type constraints in this way, is it possible with 
>> generic types? Yep! Generic types satisfy this without a problem. However, 
>> since we don't have generic protocols, we have to use a generic abstract 
>> base class to represent the same concept — an abstract container generic on 
>> the type of key which dynamically dispatches to the "real" subclassed type
>> 
>> Hopes that gives some simplified insight into the nature of this decision.
>> 
>> I see. Protocols with associated types serve the same purpose as generic 
>> interfaces in other languages, but we don't have the first-class support for 
>> protocol types with associated type constraints (a value of type `Container 
>> where Key == K`). That's something we'd like to eventually support. In other 
>> places in the standard library, we wrtie the type-erased container by hand, 
>> which is why we have `AnySequence`, `AnyCollection`, and `AnyHashable`. You 
>> could probably do something similar here; that would be a bit awkward for 
>> implementers, but might be easier to migrate forward to where we eventually 
>> want to be with the language.
>> 
>> -Joe
>> 
>> Yep, that’s a good way to describe it.
>> We could potentially do that as well, but adding another type like 
>> AnyHashable or AnyCollection felt like a much more sweeping change, 
>> considering that those require some special compiler magic themselves (and 
>> we’d like to do as little of that as we can).
> 
> AnyCollection doesn't have any special compiler magic. AnyHashable's only 
> magic is that it has implicit conversions, but that would become normal 
> behavior once it can be replaced by a plain Hashable existential type.

Hey Itai. I am not sure if I missed this. But did you follow up with why you 
didn't want to use AnyCollection/AnyHashable? The thread got really long pretty 
fast.

Michael

> 
> -Joe
> _______________________________________________
> 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

Reply via email to