> On Mar 17, 2017, at 12:49 PM, Itai Ferber <[email protected]> wrote: > > On 17 Mar 2017, at 12:18, Michael Gottesman wrote: > > > 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. > > I responded to this in a different part of the thread very recently. Can you > elaborate on how a type like AnyCollection/AnyHashable would help here? More > important than the type erasure is the type being generic on the key type, > and this must be specified. How would this be possible? > >
Thanks, let me read back. Sometimes these really long threads get confusing to me. I appreciate your patience. Michael > > Michael > -Joe > _______________________________________________ > swift-evolution mailing list > [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
