[swift-evolution] [Proposal] Foundation Swift Archival & Serialization
Itai Ferber
iferber at apple.com
Fri Mar 17 14:49:03 CDT 2017
On 17 Mar 2017, at 12:18, Michael Gottesman wrote:
>> On Mar 16, 2017, at 10:23 AM, Joe Groff via swift-evolution
>> <swift-evolution at swift.org> wrote:
>>
>>
>>> On Mar 16, 2017, at 10:21 AM, Itai Ferber <iferber at apple.com> wrote:
>>>
>>> On 15 Mar 2017, at 19:12, Joe Groff wrote:
>>>
>>>
>>> On Mar 15, 2017, at 6:46 PM, Itai Ferber <iferber at apple.com> 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?
> Michael
>
>>
>> -Joe
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170317/c2545a1c/attachment.html>
More information about the swift-evolution
mailing list