> 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
