> On Jun 8, 2017, at 8:27 AM, Gwendal Roué via swift-evolution 
> <[email protected]> wrote:
>> 
>> Le 8 juin 2017 à 16:51, James Froggatt via swift-evolution 
>> <[email protected]> a écrit :
>> 
>> Here, container is stored as a `let` value, and uses reference semantics, 
>> while the proposal also clearly lists these `encode` methods as mutating. 
>> With the current implementation of the proposal, the container must be 
>> stored as a `var`, which leads to code like the following:
>> 
>>   var container = encoder.singleValueContainer()
>>   try container.encode(data)
> 
> Yes, practically speaking and with latest Swift 4, the container needs to be 
> declared as `var`.
> 
> I admit it's weird, and feels unnatural:
> 
>   public func encode(to encoder: Encoder) throws {
>       // A mutated value that nobody consumes: so weird.
>       var container = encoder.container(keyedBy: CodingKeys.self)
>       try container.encode(latitude, forKey: .latitude)
>       try container.encode(longitude, forKey: .longitude)
>   }
> 
>> This clearly wont work as expected if the container were to have value 
>> semantics, and writing code like this feels plain wrong. Is SE-0166 really 
>> intended to work with referrence-type encoders only?
> 
> Actually, it can work with encoder/containers that have value semantics, and 
> forward the mutations somewhere else (for example to a closure which fills a 
> mutating container).
> 
> But this is again bizarre, and contrieved: 
> https://github.com/groue/GRDB.swift/blob/15bfe5f6cf76070cfb17216223bdebc6b158d654/GRDB/Record/Persistable%2BEncodable.swift
>  
> <https://github.com/groue/GRDB.swift/blob/15bfe5f6cf76070cfb17216223bdebc6b158d654/GRDB/Record/Persistable%2BEncodable.swift>
> 
> You make me think that those structs should swiftly be refactored into 
> reference types.


I made precisely this comment during the review. The response was that the 
container could potentially defined by a struct that contains some state which 
it uses to write into a reference. For instance, imagine a type like this:

        class MyEncoder: Encoder {
                var buffer: Data
                
                struct KeyedEncodingContainer<K: CodingKey>: 
KeyedEncodingContainerProtocol {
                        let encoder: MyEncoder
                        var bufferOffset: Int
                        
                        mutating func encode(_ value: String, forKey key: K) 
throws {
                                let newData = try makeDataFrom(value, forKey: 
key)
                                
                                encoder.buffer.insert(newData, at: offset)
                                bufferOffset += newData.count
                        }
                        …
                }
                …
        }

I argued that foreclosing designs like this would be acceptable—you could 
either make `KeyedEncodingContainer` a class or move `offset` into `MyEncoder` 
to get around it—but the proposers preferred to preserve this flexibility.

-- 
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to