> On 20 Mar 2017, at 02:09, Matthew Johnson via swift-evolution 
> <[email protected]> wrote:
> 
> 
>>> On Mar 19, 2017, at 2:21 PM, Tony Parker <[email protected]> wrote:
>>> 
>>> 
>>> On Mar 19, 2017, at 12:14 PM, Matthew Johnson <[email protected]> 
>>> wrote:
>>> 
>>> 
>>> 
>>> Sent from my iPhone
>>> 
>>>> On Mar 19, 2017, at 10:47 AM, Tony Parker <[email protected]> wrote:
>>>> 
>>>> Hi Matthew, Brent,
>>>> 
>>>> I see why you are asking for this Context parameter, but putting it into 
>>>> the basic Codable protocol introduces too much conceptual overhead. There 
>>>> are too many benefits to keeping adoption to just one protocol, including 
>>>> discoverability, ease of use, reducing the need for overloads on protocols 
>>>> elsewhere, and more. Supporting this one use case does not outweigh those 
>>>> benefits, especially considering I expect that most library code would not 
>>>> use it (as you say: it would be weird to pass this context between 
>>>> modules).
>>>> 
>>>> Can you figure out a way to get the context info passed through the 
>>>> encoder/decoder instead? It would make more sense as something optionally 
>>>> retrieved from the encoder/decoder that was set at the top level.
>>> 
>>> Hi Tony.  I can see the argument that the this is a feature that should be 
>>> relatively rarely used and thus should have as simple a design as possible.
>>> 
>>> If you feel like the impact of threading a typed context on the API surface 
>>> area is too heavy you could just add a `var context: Any? { get }` 
>>> requirement to Encoder and Decoder.  The expectation is that encoders and 
>>> decoders would accept a context in the top level call and make it available 
>>> to all Codable types.  This would solve the problem with minimal API impact 
>>> at the cost of the ability to statically verify that all types receive the 
>>> context they need to encode / decode correctly.
>>> 
>>> I much prefer the static safety but having a solution is better than not 
>>> having one.  :)
>> 
>> The Any context property is reasonable, but it would be nice to find 
>> something in the middle. =)
>> 
>> One other possibility is that we define a user info dictionary instead, with 
>> a custom key type that can be extended (much like our string enumerations). 
>> In general I haven’t been a fan of the user info pattern in Swift because of 
>> the necessity to cast, but as you say it’s better than nothing. e.g. 
>> userInfo : [CodingUserInfoKey: Any].
> 
> This makes sense some sense.  This would allow us to support the multiple 
> context use case.  I think the need for that is far more rare than the need 
> for a single context but it still makes sense to support it.

I'm not a fan of the info dictionary as it penalizes the simple cases of a 
unique context type.

> The down side I can see is that it could encourage users to adopt a “context 
> dictionary” approach with a bunch of keys rather than defining their own 
> context type using a single key.  This is generally a bad idea and should be 
> discouraged.
> 
> I think we should make the more common single-content use case more 
> convenient and subtly nudge users in the right direction by making it easier 
> to use.  We could do this by defining a `DefaultContext` key, including a 
> `defaultContext` property on `Encoder` and `Decoder` in an extension which 
> returns `self.context[DefaultContext]` and encouraging encoders and decoders 
> to provide an override that takes a single `context: Any` argument which gets 
> placed in the context dictionary using that key.
> 
> I still very much prefer the stronger guarantees offered by Brent’s first 
> design but I could live with this.
> 
> One last thought - might it be possible to restructure the design a way that 
> would allow us to build type-safe context-awareness on top of existing 
> encoders / decoders?  I’m going to give a little bit of thought to this but 
> don’t expect to come up with a good answer.
> 
> At least one hurdle to this in the current proposal is that the Foundation 
> encoders and decoders hide the types that actually do the encoding and 
> decoding.  There are probably very good reasons for this of course, but they 
> also make it more difficult to layer functionality like context-awareness on 
> top of them.  We would have to resort to a hack of some kind to even attempt 
> it.
> 
>> 
>> - Tony
>> 
>>> 
>>>> 
>>>> - Tony
>>>> 
>>>>>> On Mar 17, 2017, at 5:56 PM, Matthew Johnson via swift-evolution 
>>>>>> <[email protected]> wrote:
>>>>>> 
>>>>>> 
>>>>>>> On Mar 17, 2017, at 6:15 PM, Brent Royal-Gordon 
>>>>>>> <[email protected]> wrote:
>>>>>>> 
>>>>>>>> On Mar 17, 2017, at 3:35 PM, Matthew Johnson <[email protected]> 
>>>>>>>> wrote:
>>>>>>>> 
>>>>>>>> In all seriousness, I see the design as very slightly weak, in that it 
>>>>>>>> makes it easy to forget to pass a context through, but quite 
>>>>>>>> acceptable. 
>>>>>>> 
>>>>>>> Easy for who?  I was not requiring Codable types to thread it through 
>>>>>>> at all.  The context was fully managed by the Encoder / Decoder type.  
>>>>>>> The only place Codable types work with the context is as an argument 
>>>>>>> they receive.  They never pass it when encoding or decoding anything.  
>>>>>>> The Encoder / Decoder would need to store the context internally and 
>>>>>>> when call is made to encode / decode a ContextAwareCodable it would 
>>>>>>> pass the result of a dynamic cast to ContextAwareCodable.Context as the 
>>>>>>> context.
>>>>>> 
>>>>>> Oh, I see. Sorry, I missed that when I was looking at your design.
>>>>>> 
>>>>>> In practice, in my design, you would only need to manually pass a 
>>>>>> context to `encode(_:forKey:with:)` if the context was of a different 
>>>>>> type than `self`’s. 
>>>>> 
>>>>> Oh, I see.  I missed that part of your design.  I really like it with the 
>>>>> shorthands.  I’m fully on board with this being the right way to handle 
>>>>> contexts now.  I think Context should be in the basic Codable protocol.  
>>>>> That leaves the question of what to do with NSKeyedArchiver and 
>>>>> NSKeyedUnarchiver.  I’m not sure what the answer is for those but it 
>>>>> would be unfortunate to see the design compromised solely because of a 
>>>>> requirement to interoperate with them.
>>>>> 
>>>>>> This would probably happen at module or subsystem boundaries. Imagine, 
>>>>>> for instance, that your FooKit module (for interacting with the foo.io 
>>>>>> web service) needs to encode a GeoKit.Location instance, but both FooKit 
>>>>>> and GeoKit need information from a context to encode themselves 
>>>>>> properly, and they use different context types. When FooKit encoded a 
>>>>>> GeoKit.Location, it could construct and pass a GeoKit context.
>>>>>> 
>>>>>> I believe that in your design, unless the FooKit context was a subtype 
>>>>>> of the GeoKit context, you wouldn't be able to get GeoKit.Location to do 
>>>>>> the right thing.
>>>>> 
>>>>> Right.  It was assuming only one context would be needed for an entire 
>>>>> encoding / decoding process.  I don’t know of use cases where one module 
>>>>> could meaningfully provide a context to another module unless they were 
>>>>> very closely related (i.e. built as parts of the same system) but maybe 
>>>>> they do exist.  Your design is able to accommodate this very well.
>>>>> 
>>>>> I made some compromises to try and diverge from the current proposal as 
>>>>> little as possible while still solving the primary use cases I’m aware 
>>>>> of.  Now that I understand your design I think it has enough advantages 
>>>>> that we should go in that direction.  And we certainly should not go in 
>>>>> the direction of something that requires Any.
>>>>> 
>>>>>> 
>>>>>> If that weren't the case—if you were encoding a type with a matching 
>>>>>> context, or with a `Void` context—you could use the two convenience 
>>>>>> methods, which would handle the context argument for you. So threading 
>>>>>> contexts would only be necessary in a relatively rare case.
>>>>> 
>>>>> Yep, that’s very elegant!
>>>>> 
>>>>>> 
>>>>>> -- 
>>>>>> Brent Royal-Gordon
>>>>>> Architechies
>>>>>> 
>>>>> 
>>>>> _______________________________________________
>>>>> 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
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to