Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-04-04 Thread Zach Waldowski via swift-evolution
OK, understood. Thanks!



Zach



On Tue, Apr 4, 2017, at 05:53 PM, Itai Ferber wrote:

> Hi Zach,



> Thanks for your comments!

>  The type is called "unkeyed", but I assume "nonkeyed" was a typo and
>  that's what you meant. As far as the phrasing of "ordered" and
>  "sequential", both sound good, but:


>  1. The symmetry between "keyed" and "unkeyed" is helpful in creating
> opposition between types of encoding (and especially so in
> comparison to "single value", which is the odd man out — and you'd
> extremely rarely need to interact with it)
>  2. Given something that's "x" or "not x", you'd generally gravitate
> toward the thing with the more positive phrasing. As you mention,
> we really want to encourage keyed containers and diminish the use
> of unkeyed containers unless truly necessary, because they're
> fragile. The problem is, it's much easier to use the unkeyed
> containers — especially accidentally as a novice, since they're
> much simpler API — and I think "ordered" and "sequential" don't go
> far enough to detract from their usage.
> They sound good, and in fact, too good, and we find that more negative
> phrasing is helpful.
> — Itai



> On 3 Apr 2017, at 16:01, Zach Waldowski via swift-evolution wrote:



> 



> 

>> Itai and co:

>> 

>> This is a solid improvement.

>> 

>> I think it's appropriate to diminish the importance of non-keyed
>> containers. "Nonkeyed" as the name is pretty iffy to me, though, even
>> though I admit it makes the use case pretty clear. "Ordered" or
>> "Sequential" both sound fine, even for an encoder that's slot-based
>> instead of  NSArchiver-like model. An array is ordered but you don't
>> have to traverse it in order.
>> 

>> Best,

>>   Zachary Waldowski

>>   z...@waldowski.me

>> 

>> 

>> On Mon, Apr 3, 2017, at 04:31 PM, Itai Ferber via swift-
>> evolution wrote:
>>> Hi everyone,



>>> With feedback from swift-evolution and additional internal review,
>>> we've pushed updates to this proposal, and to the Swift Encoders[1]
>>> proposal. In the interest of not blowing up mail clients with the
>>> full HTML again, I'll simply be linking to the swift-evolution PR
>>> here[2], as well as the specific diff[3] of what's changed.
>>> At a high level:


>>>  * The Codable protocol has been split up into Encodable and
>>>Decodable
>>>  * String keys on CodingKey are no longer optional
>>>  * KeyedEncodingContainer has become
>>>KeyedEncodingContainerProtocol, with a concrete type-erased
>>>KeyedEncodingContainer struct to hold it
>>>  * Array responsibilities have been removed from
>>>KeyedEncodingContainer, and have been added to a new
>>>UnkeyedEncodingContainer type
>>>  * codingKeyContext has been renamed codingPath
>>> There are some specific changes inline — I know it might be a bit of
>>> a pain, but let's keep discussion here on the mailing list instead
>>> of on GitHub. We'll be looking to start the official review process
>>> very soon, so we're interested in any additional feedback.
>>> Thanks!



>>> — Itai



>>> _

>>> swift-evolution mailing list

>>> swift-evolution@swift.org

>>> https://lists.swift.org/mailman/listinfo/swift-evolution

>> 

>> 

> ___

>  swift-evolution mailing list

>  swift-evolution@swift.org

> https://lists.swift.org/mailman/listinfo/swift-evolution



> 




Links:

  1. https://github.com/apple/swift-evolution/pull/640
  2. https://github.com/apple/swift-evolution/pull/639
  3. 
https://github.com/apple/swift-evolution/pull/639/commits/d619eef9166f8b45ffac152d06376cbdab536241
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-04-04 Thread Itai Ferber via swift-evolution

Hi Zach,

Thanks for your comments!
The type is called "unkeyed", but I assume "nonkeyed" was a typo and 
that's what you meant. As far as the phrasing of "ordered" and 
"sequential", both sound good, but:


1. The symmetry between "keyed" and "unkeyed" is helpful in creating 
opposition between types of encoding (and especially so in comparison to 
"single value", which is the odd man out — and you'd extremely rarely 
need to interact with it)
2. Given something that's "x" or "not x", you'd generally gravitate 
toward the thing with the more positive phrasing. As you mention, we 
really want to encourage keyed containers and diminish the use of 
unkeyed containers unless truly necessary, because they're fragile. The 
problem is, it's much easier to use the unkeyed containers — 
especially accidentally as a novice, since they're much simpler API — 
and I think "ordered" and "sequential" don't go far enough to detract 
from their usage.


They sound good, and in fact, too good, and we find that more negative 
phrasing is helpful.


— Itai

On 3 Apr 2017, at 16:01, Zach Waldowski via swift-evolution wrote:


Itai and co:



This is a solid improvement.



I think it's appropriate to diminish the importance of non-keyed
containers. "Nonkeyed" as the name is pretty iffy to me, though, even
though I admit it makes the use case pretty clear. "Ordered" or
"Sequential" both sound fine, even for an encoder that's slot-based
instead of  NSArchiver-like model. An array is ordered but you don't
have to traverse it in order.


Best,

  Zachary Waldowski

  z...@waldowski.me





On Mon, Apr 3, 2017, at 04:31 PM, Itai Ferber via swift-evolution 
wrote:

Hi everyone,





With feedback from swift-evolution and additional internal review,
we've pushed updates to this proposal, and to the Swift Encoders[1]
proposal. In the interest of not blowing up mail clients with the 
full

HTML again, I'll simply be linking to the swift-evolution PR here[2],
as well as the specific diff[3] of what's changed.
At a high level:



 * The Codable protocol has been split up into Encodable and 
Decodable

 * String keys on CodingKey are no longer optional
 * KeyedEncodingContainer has become
   KeyedEncodingContainerProtocol, with a concrete type-erased
   KeyedEncodingContainer struct to hold it
 * Array responsibilities have been removed from
   KeyedEncodingContainer, and have been added to a new
   UnkeyedEncodingContainer type
 * codingKeyContext has been renamed codingPath
There are some specific changes inline — I know it might be a bit 
of a
pain, but let's keep discussion here on the mailing list instead of 
on

GitHub. We'll be looking to start the official review process very
soon, so we're interested in any additional feedback.
Thanks!





— Itai





_



swift-evolution mailing list



swift-evolution@swift.org



https://lists.swift.org/mailman/listinfo/swift-evolution





Links:

  1. https://github.com/apple/swift-evolution/pull/640
  2. https://github.com/apple/swift-evolution/pull/639
  3. 
https://github.com/apple/swift-evolution/pull/639/commits/d619eef9166f8b45ffac152d06376cbdab536241




___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-04-03 Thread Zach Waldowski via swift-evolution
Itai and co:



This is a solid improvement.



I think it's appropriate to diminish the importance of non-keyed
containers. "Nonkeyed" as the name is pretty iffy to me, though, even
though I admit it makes the use case pretty clear. "Ordered" or
"Sequential" both sound fine, even for an encoder that's slot-based
instead of  NSArchiver-like model. An array is ordered but you don't
have to traverse it in order.


Best,

  Zachary Waldowski

  z...@waldowski.me





On Mon, Apr 3, 2017, at 04:31 PM, Itai Ferber via swift-evolution wrote:
> Hi everyone,



> With feedback from swift-evolution and additional internal review,
> we've pushed updates to this proposal, and to the Swift Encoders[1]
> proposal. In the interest of not blowing up mail clients with the full
> HTML again, I'll simply be linking to the swift-evolution PR here[2],
> as well as the specific diff[3] of what's changed.
> At a high level:


>  * The Codable protocol has been split up into Encodable and Decodable
>  * String keys on CodingKey are no longer optional
>  * KeyedEncodingContainer has become
>KeyedEncodingContainerProtocol, with a concrete type-erased
>KeyedEncodingContainer struct to hold it
>  * Array responsibilities have been removed from
>KeyedEncodingContainer, and have been added to a new
>UnkeyedEncodingContainer type
>  * codingKeyContext has been renamed codingPath
> There are some specific changes inline — I know it might be a bit of a
> pain, but let's keep discussion here on the mailing list instead of on
> GitHub. We'll be looking to start the official review process very
> soon, so we're interested in any additional feedback.
> Thanks!



> — Itai



> _

> swift-evolution mailing list

> swift-evolution@swift.org

> https://lists.swift.org/mailman/listinfo/swift-evolution




Links:

  1. https://github.com/apple/swift-evolution/pull/640
  2. https://github.com/apple/swift-evolution/pull/639
  3. 
https://github.com/apple/swift-evolution/pull/639/commits/d619eef9166f8b45ffac152d06376cbdab536241
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-04-03 Thread Itai Ferber via swift-evolution
Hi everyone,

With feedback from swift-evolution and additional internal review, we've pushed 
updates to this proposal, and to the Swift Encoders 
 proposal.
In the interest of not blowing up mail clients with the full HTML again, I'll 
simply be linking to the swift-evolution PR here 
, as well as the specific 
diff 

 of what's changed.

At a high level:

The Codable protocol has been split up into Encodable and Decodable
String keys on CodingKey are no longer optional
KeyedEncodingContainer has become KeyedEncodingContainerProtocol, with a 
concrete type-erased KeyedEncodingContainer struct to hold it
Array responsibilities have been removed from KeyedEncodingContainer, and have 
been added to a new UnkeyedEncodingContainer type
codingKeyContext has been renamed codingPath
There are some specific changes inline — I know it might be a bit of a pain, 
but let's keep discussion here on the mailing list instead of on GitHub.
We'll be looking to start the official review process very soon, so we're 
interested in any additional feedback.

Thanks!

— Itai___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-24 Thread Ben Rimmington via swift-evolution

> On 23 Mar 2017, at 19:37, Ben Rimmington wrote:
> 
>> On 22 Mar 2017, at 17:41, Itai Ferber wrote:
>> 
>> What’s the use case that you were thinking of? KeyPaths could be useful in 
>> the case where you don’t need to customize your key names, but cannot 
>> represent a custom case like
>> 
>> public struct Post {
>> var authorID: Int
>> var bodyText: String
>> 
>> private enum CodingKeys : String, CodingKey {
>> case authorID = "author_id"
>> case bodyText = "body_text"
>> }
>> }
>> Or am I misunderstanding?
>> 
> 
> For custom names, the `CodingKeys` enum does seem like the best design, 
> unless an attribute can be used.
> 
>   public struct Post : Codable {
>   @codable(name: "author_id") var authorID: Int
>   @codable(name: "body_text") var bodyText: String
>   }
> 
> If each `KeyPath` encapsulates the type information, the `decode` methods 
> won't need a `type` parameter.
> 
>   /// Primitive decoding methods (for single-value and keyed containers).
>   open class DecodingContainer {
>   open func decode(for keyPath: KeyPath)   throws -> Bool
>   open func decode(for keyPath: KeyPath)throws -> Int
>   open func decode(for keyPath: KeyPath)   throws -> UInt
>   open func decode(for keyPath: KeyPath)  throws -> Float
>   open func decode(for keyPath: KeyPath) throws -> 
> Double
>   open func decode(for keyPath: KeyPath) throws -> 
> String
>   open func decode(for keyPath: KeyPath)   throws -> Data
>   }
> 
>   /// Keyed containers inherit the primitive decoding methods.
>   open class KeyedDecodingContainer : DecodingContainer {
>   open func decode(for keyPath: KeyPath Value>) throws -> Value
>   }

On second thought, "property behaviors" 

 could eventually allow the custom name to be stored in a `KeyPath` subclass.

Key paths would also need `LosslessStringConvertible` conformance. The current 
design only has `CustomDebugStringConvertible` conformance.

-- Ben

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-23 Thread Oliver Jones via swift-evolution
Fantastic. Great to hear. I look forward to reading the revised proposal!

Regards

> On 24 Mar 2017, at 3:34 am, Itai Ferber  wrote:
> 
> Hi Oliver,
> 
> Thanks for your comments! We thought about this and we agree overall — we 
> will incorporate this suggestion along with others in the next batch update 
> as long as nothing prohibitive comes up.
> 
> — Itai
> 
> On 23 Mar 2017, at 7:49, Oliver Jones wrote:
> 
> Like everyone I’m excited by this new proposal.  But…
> 
> > protocol Codable: Adopted by types to opt into archival. Conformance may be 
> > automatically derived in cases where all properties are also Codable.
> 
> … can I make one suggestion.  Please do not repeat the mistakes of NSCoding 
> in combining the encoding and decoding into a single protocol.  Just as there 
> are Encoder and Decoder classes their should be Encodable and Decodable 
> protocols (maybe have an aggregate Codable protocol for convenience but do 
> not force it).
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-23 Thread Jonathan Hull via swift-evolution
Let me vote +1 for splitting it.  The added conceptual complexity should be 
minimal, since it is progressively disclosed.  You only need to know about 
codeable, unless you run into the issue where you only want one, at which point 
stack overflow, etc… will point you to Encodable/Decodable and you will be glad 
they exist.


> On Mar 23, 2017, at 11:44 AM, Tony Parker via swift-evolution 
>  wrote:
> 
> Hi Oliver,
> 
>> On Mar 23, 2017, at 7:55 AM, Oliver Jones via swift-evolution 
>> > wrote:
>> 
>> Like everyone I’m excited by this new proposal.  But…
>> 
>> > protocol Codable: Adopted by types to opt into archival. Conformance may 
>> > be automatically derived in cases where all properties are also Codable.
>> 
>> … can I make one suggestion.  Please do not repeat the mistakes of NSCoding 
>> in combining the encoding and decoding into a single protocol.  Just as 
>> there are Encoder and Decoder classes their should be Encodable and 
>> Decodable protocols (maybe have an aggregate Codable protocol for 
>> convenience but do not force it).
>> 
>> My reasoning:
>> 
>> Sometimes you only want to decode or encode and object and not vice versa.  
>> This is often the case with Web APIs and JSON serialisation.  
>> 
>> Eg:
>> 
>> Often an app only consumes (decodes) JSON encoded objects and never writes 
>> them out (a read only app for example). So the encode(to:) methods are 
>> completely redundant and someone adopting Codable should not be forced to 
>> write them.  
>> 
>> If only I had a dollar for all the times I’ve seen this sort of code in 
>> projects:
>> 
>> class MyClass : NSCoding {
>> init?(coder: NSCoder) {
>>   // ... some decoding code
>> }
>> 
>> func encode(with aCoder: NSCoder) {
>>preconditionFailure(“Not implemented”)
>> }
>> }
>> 
>> 
>> Another example: 
>> 
>> Web APIs often take data in a different structure as input (i.e. “Request” 
>> objects) than they output.  These request objects are only ever encoded and 
>> never decoded by an application so implementing init(from:) is completely 
>> redundant.
>> 
>> Personally I think the approach taken by libraries like Wrap 
>> (https://github.com/johnsundell/wrap ) 
>> and Unbox (https://github.com/JohnSundell/Unbox 
>> ) is a much better design.  Encoding 
>> and decoding should not be the same protocol.
>> 
>> Yes I understand that Codable could provide no-op (or preconditionFailure) 
>> protocol extension based default implementations of init(from:) and 
>> encode(to:) (or try to magic up implementations based on the Codable nature 
>> of public properties as suggested in the proposal) but to me that seems like 
>> a hack that is papering over bad design.  I think this joint Codable design 
>> probably fails the Liskov substitution principle too.
>> 
>> So I again implore you to consider splitting Codable into two protocols, one 
>> for encoding and another for decoding.
>> 
>> Sorry if I’m repeating what other people have already said.  I’ve not read 
>> every response to this proposal on the list.
>> 
>> Regards
> 
> Thanks for your feedback. We are indeed considering splitting this up into 3 
> protocols instead of 1 (“Encodable", “Decodable", "Codable : Encodable, 
> Decodable”).
> 
> The main counterpoint is the additional complexity inherent in this approach. 
> We are considering if the tradeoff is worth it.
> 
> - Tony
> 
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org 
> https://lists.swift.org/mailman/listinfo/swift-evolution 
> 
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-23 Thread Ben Rimmington via swift-evolution

> On 22 Mar 2017, at 17:41, Itai Ferber wrote:
> 
> What’s the use case that you were thinking of? KeyPaths could be useful in 
> the case where you don’t need to customize your key names, but cannot 
> represent a custom case like
> 
> public struct Post {
> var authorID: Int
> var bodyText: String
> 
> private enum CodingKeys : String, CodingKey {
> case authorID = "author_id"
> case bodyText = "body_text"
> }
> }
> Or am I misunderstanding?
> 

For custom names, the `CodingKeys` enum does seem like the best design, unless 
an attribute can be used.

public struct Post : Codable {
@codable(name: "author_id") var authorID: Int
@codable(name: "body_text") var bodyText: String
}

If each `KeyPath` encapsulates the type information, the `decode` methods won't 
need a `type` parameter.

/// Primitive decoding methods (for single-value and keyed containers).
open class DecodingContainer {
open func decode(for keyPath: KeyPath)   throws -> Bool
open func decode(for keyPath: KeyPath)throws -> Int
open func decode(for keyPath: KeyPath)   throws -> UInt
open func decode(for keyPath: KeyPath)  throws -> Float
open func decode(for keyPath: KeyPath) throws -> 
Double
open func decode(for keyPath: KeyPath) throws -> 
String
open func decode(for keyPath: KeyPath)   throws -> Data
}

/// Keyed containers inherit the primitive decoding methods.
open class KeyedDecodingContainer : DecodingContainer {
open func decode(for keyPath: KeyPath) throws -> Value
}

-- Ben

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-23 Thread Tony Parker via swift-evolution
Hi Oliver,

> On Mar 23, 2017, at 7:55 AM, Oliver Jones via swift-evolution 
>  wrote:
> 
> Like everyone I’m excited by this new proposal.  But…
> 
> > protocol Codable: Adopted by types to opt into archival. Conformance may be 
> > automatically derived in cases where all properties are also Codable.
> 
> … can I make one suggestion.  Please do not repeat the mistakes of NSCoding 
> in combining the encoding and decoding into a single protocol.  Just as there 
> are Encoder and Decoder classes their should be Encodable and Decodable 
> protocols (maybe have an aggregate Codable protocol for convenience but do 
> not force it).
> 
> My reasoning:
> 
> Sometimes you only want to decode or encode and object and not vice versa.  
> This is often the case with Web APIs and JSON serialisation.  
> 
> Eg:
> 
> Often an app only consumes (decodes) JSON encoded objects and never writes 
> them out (a read only app for example). So the encode(to:) methods are 
> completely redundant and someone adopting Codable should not be forced to 
> write them.  
> 
> If only I had a dollar for all the times I’ve seen this sort of code in 
> projects:
> 
> class MyClass : NSCoding {
> init?(coder: NSCoder) {
>   // ... some decoding code
> }
> 
> func encode(with aCoder: NSCoder) {
>preconditionFailure(“Not implemented”)
> }
> }
> 
> 
> Another example: 
> 
> Web APIs often take data in a different structure as input (i.e. “Request” 
> objects) than they output.  These request objects are only ever encoded and 
> never decoded by an application so implementing init(from:) is completely 
> redundant.
> 
> Personally I think the approach taken by libraries like Wrap 
> (https://github.com/johnsundell/wrap ) 
> and Unbox (https://github.com/JohnSundell/Unbox 
> ) is a much better design.  Encoding 
> and decoding should not be the same protocol.
> 
> Yes I understand that Codable could provide no-op (or preconditionFailure) 
> protocol extension based default implementations of init(from:) and 
> encode(to:) (or try to magic up implementations based on the Codable nature 
> of public properties as suggested in the proposal) but to me that seems like 
> a hack that is papering over bad design.  I think this joint Codable design 
> probably fails the Liskov substitution principle too.
> 
> So I again implore you to consider splitting Codable into two protocols, one 
> for encoding and another for decoding.
> 
> Sorry if I’m repeating what other people have already said.  I’ve not read 
> every response to this proposal on the list.
> 
> Regards

Thanks for your feedback. We are indeed considering splitting this up into 3 
protocols instead of 1 (“Encodable", “Decodable", "Codable : Encodable, 
Decodable”).

The main counterpoint is the additional complexity inherent in this approach. 
We are considering if the tradeoff is worth it.

- Tony


___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-23 Thread Itai Ferber via swift-evolution

Hi Oliver,

Thanks for your comments! We thought about this and we agree overall — 
we will incorporate this suggestion along with others in the next batch 
update as long as nothing prohibitive comes up.


— Itai

On 23 Mar 2017, at 7:49, Oliver Jones wrote:


Like everyone I’m excited by this new proposal.  But…

protocol Codable: Adopted by types to opt into archival. Conformance 
may be automatically derived in cases where all properties are also 
Codable.


… can I make one suggestion.  Please do not repeat the mistakes of 
NSCoding in combining the encoding and decoding into a single 
protocol.  Just as there are Encoder and Decoder classes their should 
be Encodable and Decodable protocols (maybe have an aggregate Codable 
protocol for convenience but do not force it).


My reasoning:

Sometimes you only want to decode or encode and object and not vice 
versa.  This is often the case with Web APIs and JSON serialisation.


Eg:

Often an app only consumes (decodes) JSON encoded objects and never 
writes them out (a read only app for example). So the encode(to:) 
methods are completely redundant and someone adopting Codable should 
not be forced to write them.


If only I had a dollar for all the times I’ve seen this sort of code 
in projects:


class MyClass : NSCoding {
init?(coder: NSCoder) {
  // ... some decoding code
}

func encode(with aCoder: NSCoder) {
   preconditionFailure(“Not implemented”)
}
}


Another example:

Web APIs often take data in a different structure as input (i.e. 
“Request” objects) than they output.  These request objects are 
only ever encoded and never decoded by an application so implementing 
init(from:) is completely redundant.


Personally I think the approach taken by libraries like Wrap 
(https://github.com/johnsundell/wrap) and Unbox 
(https://github.com/JohnSundell/Unbox) is a much better design.  
Encoding and decoding should not be the same protocol.


Yes I understand that Codable could provide no-op (or 
preconditionFailure) protocol extension based default implementations 
of init(from:) and encode(to:) (or try to magic up implementations 
based on the Codable nature of public properties as suggested in the 
proposal) but to me that seems like a hack that is papering over bad 
design.  I think this joint Codable design probably fails the Liskov 
substitution principle too.


So I again implore you to consider splitting Codable into two 
protocols, one for encoding and another for decoding.


Sorry if I’m repeating what other people have already said.  I’ve 
not read every response to this proposal on the list.


Regards



___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-22 Thread Itai Ferber via swift-evolution

Hi Ben,

What’s the use case that you were thinking of? `KeyPath`s could be 
useful in the case where you don’t need to customize your key names, 
but cannot represent a custom case like


```swift
public struct Post {
var authorID: Int
var bodyText: String

private enum CodingKeys : String, CodingKey {
case authorID = "author_id"
case bodyText = "body_text"
}
}
```

Or am I misunderstanding?

— Itai

On 22 Mar 2017, at 5:39, Ben Rimmington wrote:


On 15 Mar 2017, at 22:40, Itai Ferber wrote:

The following introduces a new Swift-focused archival and 
serialization API as part of the Foundation framework. We’re 
interested in improving the experience and safety of performing 
archival and serialization, and are happy to receive community 
feedback on this work.


Instead of a CodingKeys enum, could the KeyPath proposal 
 be utilized 
somehow?


-- Ben
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-22 Thread Ben Rimmington via swift-evolution

> On 15 Mar 2017, at 22:40, Itai Ferber wrote:
> 
> The following introduces a new Swift-focused archival and serialization API 
> as part of the Foundation framework. We’re interested in improving the 
> experience and safety of performing archival and serialization, and are happy 
> to receive community feedback on this work.

Instead of a CodingKeys enum, could the KeyPath proposal 
 be utilized somehow?

-- Ben

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-21 Thread Colin Barrett via swift-evolution
Hi Itai,

On Tue, Mar 21, 2017 at 1:03 PM Itai Ferber  wrote:

Hi Colin,

Thanks for your comments! Are you talking about Codable synthesis, or
encoding in general?

Yeah, I meant specifically in the case where things are synthesized
automatically. As you point out below, if someone implements a custom
Codeable instance, all bets are off.

On 21 Mar 2017, at 8:44, Colin Barrett wrote:

Hi Itai,

Glad to see these proposal! I'm curious, have you or the other Swift folks
thought about how *users* of these new Codable protocols will interact with
resilience domains?

What I mean is that what appear to be private or internal identifiers, and
thus changeable at will, may actually be fragile in that changing them will
break the ability to decode archives encoded by previous versions.

Making this safer could mean:
- Encoding only public properties

Unfortunately, property accessibility in code does not always map 1-to-1
with accessibility for archival (nor do I think they should be tied to one
another).
There are certainly cases where you’d want to include private information
in an archive, but that is not useful to expose to external clients, e.g.,
a struct/class version:

public struct MyFoo {
// Should be encoded.
public var title: String
public var identifier: Int

// This should be encoded too — in case the struct changes in the
// future, want to be able to refer to the payload version.
private let version = 1.0
}

Of course, there can also be public properties that you don’t find useful
to encode. At the moment, I’m not sure there’s a much better answer than
"the author of the code will have to think about the representation of
their data"; even if there were an easier way to annotate "I definitely
want this to be archived"/"I definitely don’t want this to be archived",
the annotation would still need to be manual.

(The above applies primarily in the case of Codable synthesis; when
implementing Codable manually I don’t think the compiler should ever
prevent you from doing what you need.)

- Adding some form of indirection (a la ObjC non-fragile ivars?)

What do you mean by this?

I'm not sure exactly how or if it would work in-detail, unfortunately, but
I know that the ObjC runtime emits symbols which are used to lookup the
offset in the object struct for non-fragile ivars. Maybe some similar form
of indirection would be useful for encoding non-public ivars. Like I said,
don't know exactly how/if that would work, just sharing :)


- Compiler warning (or disallowing) changes to properties in certain
situations.

We’ve thought about this with regards to identifying classes uniquely
across renaming, moving modules, etc.; this is a resilience problem in
general.
In order for the compiler to know about changes to your code it’d need to
keep state across compilations. While possible, this feels pretty fragile
(and potentially not very portable).

   - Compiler warns about changing a property? Blow away the cache
   directory!
   - Cloning the code to a new machine for the first time? Hmm, all the
   warnings went away…

This would be nice to have, but yes:

I imagine the specifics would need to follow the rest of the plans for
resilience.

specifics on this would likely be in line with the rest of resilience plans
for Swift in general.


Right. Thus my concern about allowing non-public fields to be automatically
serialized. The most conservative option would be to only automatically
synthesize a Codeable instance for the public members of public types.
Seems overly restrictive, so maybe anything goes for internal types, or
there's some sort of warning (overridable via an attribute?)

I want to emphasize btw that I'm enthusiastic about this proposal in
general. The support for integer keys is welcome and, as it's one of my pet
projects, eases support for a Cap'n Proto-style serialization format.[1]

-Colin

[1]: https://capnproto.org

It's likely that this could be addressed by a future proposal, as for the
time being developers can simply "not hold it wrong" ;)

Thanks,
-Colin

On Wed, Mar 15, 2017 at 6:52 PM Itai Ferber via swift-evolution <
swift-evolution@swift.org> wrote:

Hi everyone,

The following introduces a new Swift-focused archival and serialization
API as part of the Foundation framework. We’re interested in improving the
experience and safety of performing archival and serialization, and are
happy to receive community feedback on this work.

Because of the length of this proposal, the *Appendix* and *Alternatives
Considered* sections have been omitted here, but are available in the full
proposal  on the
swift-evolution repo. The full proposal also includes an *Unabridged API*
for


further consideration.

Without further ado, inlined below.

— Itai

Swift Archival & Serialization

- Proposal: SE- 
- Author(s): Itai Ferber 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-21 Thread Itai Ferber via swift-evolution

Hi Colin,

Thanks for your comments! Are you talking about `Codable` synthesis, or 
encoding in general?


On 21 Mar 2017, at 8:44, Colin Barrett wrote:


Hi Itai,

Glad to see these proposal! I'm curious, have you or the other Swift 
folks
thought about how *users* of these new Codable protocols will interact 
with

resilience domains?

What I mean is that what appear to be private or internal identifiers, 
and
thus changeable at will, may actually be fragile in that changing them 
will

break the ability to decode archives encoded by previous versions.

Making this safer could mean:
- Encoding only public properties
Unfortunately, property accessibility in code does not always map 1-to-1 
with accessibility for archival (nor do I think they should be tied to 
one another).
There are certainly cases where you’d want to include private 
information in an archive, but that is not useful to expose to external 
clients, e.g., a struct/class version:


```swift
public struct MyFoo {
// Should be encoded.
public var title: String
public var identifier: Int

// This should be encoded too — in case the struct changes in the
// future, want to be able to refer to the payload version.
private let version = 1.0
}
```

Of course, there can also be public properties that you don’t find 
useful to encode. At the moment, I’m not sure there’s a much better 
answer than "the author of the code will have to think about the 
representation of their data"; even if there were an easier way to 
annotate "I definitely want this to be archived"/"I definitely don’t 
want this to be archived", the annotation would still need to be manual.


(The above applies primarily in the case of `Codable` synthesis; when 
implementing `Codable` manually I don’t think the compiler should ever 
prevent you from doing what you need.)



- Adding some form of indirection (a la ObjC non-fragile ivars?)

What do you mean by this?


- Compiler warning (or disallowing) changes to properties in certain
situations.
We’ve thought about this with regards to identifying classes uniquely 
across renaming, moving modules, etc.; this is a resilience problem in 
general.
In order for the compiler to know about changes to your code it’d need 
to keep state across compilations. While possible, this feels pretty 
fragile (and potentially not very portable).


* Compiler warns about changing a property? Blow away the cache 
directory!
* Cloning the code to a new machine for the first time? Hmm, all the 
warnings went away…


This would be nice to have, but yes:


I imagine the specifics would need to follow the rest of the plans for
resilience.
specifics on this would likely be in line with the rest of resilience 
plans for Swift in general.


It's likely that this could be addressed by a future proposal, as for 
the

time being developers can simply "not hold it wrong" ;)

Thanks,
-Colin

On Wed, Mar 15, 2017 at 6:52 PM Itai Ferber via swift-evolution <
swift-evolution@swift.org> wrote:


Hi everyone,

The following introduces a new Swift-focused archival and 
serialization
API as part of the Foundation framework. We’re interested in 
improving the
experience and safety of performing archival and serialization, and 
are

happy to receive community feedback on this work.
Because of the length of this proposal, the *Appendix* and 
*Alternatives
Considered* sections have been omitted here, but are available in the 
full

proposal  on the
swift-evolution repo. The full proposal also includes an *Unabridged 
API* for

further consideration.

Without further ado, inlined below.

— Itai

Swift Archival & Serialization

   - Proposal: SE- 

   - Author(s): Itai Ferber , Michael 
LeHew
   , Tony Parker 


   - Review Manager: TBD
   - Status: *Awaiting review*
   - Associated PRs:
  - #8124 
  - #8125 

Introduction

Foundation's current archival and serialization APIs (NSCoding,
NSJSONSerialization, NSPropertyListSerialization, etc.), while 
fitting
for the dynamism of Objective-C, do not always map optimally into 
Swift.

This document lays out the design of an updated API that improves the
developer experience of performing archival and serialization in 
Swift.


Specifically:

   - It aims to provide a solution for the archival of Swift struct 
and

   enum types
   - It aims to provide a more type-safe solution for serializing to
   external formats, such as JSON and plist

Motivation

The primary motivation for this proposal is the inclusion of native 
Swift

enum and struct types in archival and serialization. Currently,
developers targeting Swift cannot participate in NSCoding without 
being
willing to abandon enum and structtypes — NSCoding is an @objc 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-21 Thread Matthew Johnson via swift-evolution

> On Mar 21, 2017, at 11:24 AM, Colin Barrett  
> wrote:
> 
> I'm not sure I follow. What do you mean "which strategy to use for a given 
> encoding"? IMO there should be at most one implementation of Coding / 
> Decoding for a particular type. So the way you'd say "I want to decode a JSON 
> response that implements my blog model" would be, reusing the definition from 
> above
> 
> let wblog = try JSONDecoder().decode(WebBlogModel.self, from: payload)
> let blog = wblog.wrapped
> 
> What am I missing?

When I have encountered a need for things like this I usually don’t need to 
encode a whole tree differently based on context.  I only need to encode one or 
two types differently based on context.  IMO it would be insane to require 
wrapper types all the way down the tree that’s getting encoded just so that one 
or two types can encode themselves using a format specified by a server.  I 
suppose you could make it work but it’s crazy and unnecessary complexity if you 
ask me.

Brent’s example was using different formats for local archiving and for cloud 
persistence.  This also seems reasonable.  Again wrappers would work but would 
also be a lot of boilerplate for no obvious win.

Encoder and Decoder as proposed already include a `codingKeyContext`.  We’re 
just asking for an additional user-defined context which gives information 
about the purpose of the encoding.

> 
> -Colin
> 
> 
> On Tue, Mar 21, 2017 at 12:16 PM Matthew Johnson  > wrote:
>> On Mar 21, 2017, at 11:00 AM, Colin Barrett via swift-evolution 
>> > wrote:
>> 
>> 
>> 
>> On Thu, Mar 16, 2017 at 3:33 PM Itai Ferber via swift-evolution 
>> > wrote:
>> 
>> Here's what I mean: Suppose I have a BlogPost model, and I can both fetch 
>> and post BlogPosts to a cross-platform web service, and store them locally. 
>> But when I fetch and post remotely, I ned to conform to the web service's 
>> formats; when I store an instance locally, I have a freer hand in designing 
>> my storage, and perhaps need to store some extra metadata. How do you 
>> imagine handling that sort of situation? Is the answer simply that I should 
>> use two different types?
>> 
>> This is a valid concern, and one that should likely be addressed.
>> 
>> Perhaps the solution is to offer a userInfo : [UserInfoKey : Any] 
>> (UserInfoKey being a String-RawRepresentable struct or similar) on Encoder 
>> and Decoder set at the top-level to allow passing this type of contextual 
>> information from the top level down.
>> 
>>  
>> I assumed that in those situations, one would create a wrapper struct,
>> 
>> struct WebBlogModel {
>> let wrapped: BlogModel
>> }
>> 
>> probably for the encoding impl that requires more custom work. The 
>> implementation of Codable for this struct would then serialize (deserialize) 
>> from (to) its wrapped value's properties directly.
>> 
>> Types already provide a means for performing context sensitive 
>> implementation selection, I don't think it's necessary to provide another 
>> way to do that in Swift. Of course I could very well be wrong :)
> 
> Wrappers like this give you a way to implement different encoding strategies 
> but they don’t help you identify which strategy to use for a given encoding.  
> You need a user-defined context to do that.  Brent has proposed a couple of 
> different designs to facilitate this which are nicer than a user info 
> dictionary.
> 
>> 
>> -Colin
> 
>> ___
>> swift-evolution mailing list
>> swift-evolution@swift.org 
>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>> 

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-21 Thread Colin Barrett via swift-evolution
I'm not sure I follow. What do you mean "which strategy to use for a given
encoding"? IMO there should be at most one implementation of Coding /
Decoding for a particular type. So the way you'd say "I want to decode a
JSON response that implements my blog model" would be, reusing the
definition from above

let wblog = try JSONDecoder().decode(WebBlogModel.self, from: payload)
let blog = wblog.wrapped

What am I missing?

-Colin


On Tue, Mar 21, 2017 at 12:16 PM Matthew Johnson 
wrote:

> On Mar 21, 2017, at 11:00 AM, Colin Barrett via swift-evolution <
> swift-evolution@swift.org> wrote:
>
>
>
> On Thu, Mar 16, 2017 at 3:33 PM Itai Ferber via swift-evolution <
> swift-evolution@swift.org> wrote:
>
>
> Here's what I mean: Suppose I have a BlogPost model, and I can both fetch
> and post BlogPosts to a cross-platform web service, and store them locally.
> But when I fetch and post remotely, I ned to conform to the web service's
> formats; when I store an instance locally, I have a freer hand in designing
> my storage, and perhaps need to store some extra metadata. How do you
> imagine handling that sort of situation? Is the answer simply that I should
> use two different types?
>
> This is a valid concern, and one that should likely be addressed.
>
> Perhaps the solution is to offer a userInfo : [UserInfoKey : Any] (
> UserInfoKey being a String-RawRepresentable struct or similar) on Encoder
> and Decoder set at the top-level to allow passing this type of contextual
> information from the top level down.
>
>
> I assumed that in those situations, one would create a wrapper struct,
>
> struct WebBlogModel {
> let wrapped: BlogModel
> }
>
> probably for the encoding impl that requires more custom work. The
> implementation of Codable for this struct would then serialize
> (deserialize) from (to) its wrapped value's properties directly.
>
> Types already provide a means for performing context sensitive
> implementation selection, I don't think it's necessary to provide another
> way to do that in Swift. Of course I could very well be wrong :)
>
>
> Wrappers like this give you a way to *implement* different encoding
> strategies but they don’t help you identify which strategy to use for a
> given encoding.  You need a user-defined context to do that.  Brent has
> proposed a couple of different designs to facilitate this which are nicer
> than a user info dictionary.
>
>
> -Colin
>
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-21 Thread Matthew Johnson via swift-evolution

> On Mar 21, 2017, at 11:00 AM, Colin Barrett via swift-evolution 
>  wrote:
> 
> 
> 
> On Thu, Mar 16, 2017 at 3:33 PM Itai Ferber via swift-evolution 
> > wrote:
> 
> Here's what I mean: Suppose I have a BlogPost model, and I can both fetch and 
> post BlogPosts to a cross-platform web service, and store them locally. But 
> when I fetch and post remotely, I ned to conform to the web service's 
> formats; when I store an instance locally, I have a freer hand in designing 
> my storage, and perhaps need to store some extra metadata. How do you imagine 
> handling that sort of situation? Is the answer simply that I should use two 
> different types?
> 
> This is a valid concern, and one that should likely be addressed.
> 
> Perhaps the solution is to offer a userInfo : [UserInfoKey : Any] 
> (UserInfoKey being a String-RawRepresentable struct or similar) on Encoder 
> and Decoder set at the top-level to allow passing this type of contextual 
> information from the top level down.
> 
>  
> I assumed that in those situations, one would create a wrapper struct,
> 
> struct WebBlogModel {
> let wrapped: BlogModel
> }
> 
> probably for the encoding impl that requires more custom work. The 
> implementation of Codable for this struct would then serialize (deserialize) 
> from (to) its wrapped value's properties directly.
> 
> Types already provide a means for performing context sensitive implementation 
> selection, I don't think it's necessary to provide another way to do that in 
> Swift. Of course I could very well be wrong :)

Wrappers like this give you a way to implement different encoding strategies 
but they don’t help you identify which strategy to use for a given encoding.  
You need a user-defined context to do that.  Brent has proposed a couple of 
different designs to facilitate this which are nicer than a user info 
dictionary.

> 
> -Colin
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-21 Thread Colin Barrett via swift-evolution
On Thu, Mar 16, 2017 at 3:33 PM Itai Ferber via swift-evolution <
swift-evolution@swift.org> wrote:

>
> Here's what I mean: Suppose I have a BlogPost model, and I can both fetch
> and post BlogPosts to a cross-platform web service, and store them locally.
> But when I fetch and post remotely, I ned to conform to the web service's
> formats; when I store an instance locally, I have a freer hand in designing
> my storage, and perhaps need to store some extra metadata. How do you
> imagine handling that sort of situation? Is the answer simply that I should
> use two different types?
>
> This is a valid concern, and one that should likely be addressed.
>
> Perhaps the solution is to offer a userInfo : [UserInfoKey : Any] (
> UserInfoKey being a String-RawRepresentable struct or similar) on Encoder
> and Decoder set at the top-level to allow passing this type of contextual
> information from the top level down.
>

I assumed that in those situations, one would create a wrapper struct,

struct WebBlogModel {
let wrapped: BlogModel
}

probably for the encoding impl that requires more custom work. The
implementation of Codable for this struct would then serialize
(deserialize) from (to) its wrapped value's properties directly.

Types already provide a means for performing context sensitive
implementation selection, I don't think it's necessary to provide another
way to do that in Swift. Of course I could very well be wrong :)

-Colin
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-21 Thread Colin Barrett via swift-evolution
Hi Itai,

Glad to see these proposal! I'm curious, have you or the other Swift folks
thought about how *users* of these new Codable protocols will interact with
resilience domains?

What I mean is that what appear to be private or internal identifiers, and
thus changeable at will, may actually be fragile in that changing them will
break the ability to decode archives encoded by previous versions.

Making this safer could mean:
- Encoding only public properties
- Adding some form of indirection (a la ObjC non-fragile ivars?)
- Compiler warning (or disallowing) changes to properties in certain
situations.

I imagine the specifics would need to follow the rest of the plans for
resilience.

It's likely that this could be addressed by a future proposal, as for the
time being developers can simply "not hold it wrong" ;)

Thanks,
-Colin

On Wed, Mar 15, 2017 at 6:52 PM Itai Ferber via swift-evolution <
swift-evolution@swift.org> wrote:

> Hi everyone,
>
> The following introduces a new Swift-focused archival and serialization
> API as part of the Foundation framework. We’re interested in improving the
> experience and safety of performing archival and serialization, and are
> happy to receive community feedback on this work.
> Because of the length of this proposal, the *Appendix* and *Alternatives
> Considered* sections have been omitted here, but are available in the full
> proposal  on the
> swift-evolution repo. The full proposal also includes an *Unabridged API* for
> further consideration.
>
> Without further ado, inlined below.
>
> — Itai
>
> Swift Archival & Serialization
>
>- Proposal: SE- 
>- Author(s): Itai Ferber , Michael LeHew
>, Tony Parker 
>- Review Manager: TBD
>- Status: *Awaiting review*
>- Associated PRs:
>   - #8124 
>   - #8125 
>
> Introduction
>
> Foundation's current archival and serialization APIs (NSCoding,
> NSJSONSerialization, NSPropertyListSerialization, etc.), while fitting
> for the dynamism of Objective-C, do not always map optimally into Swift.
> This document lays out the design of an updated API that improves the
> developer experience of performing archival and serialization in Swift.
>
> Specifically:
>
>- It aims to provide a solution for the archival of Swift struct and
>enum types
>- It aims to provide a more type-safe solution for serializing to
>external formats, such as JSON and plist
>
> Motivation
>
> The primary motivation for this proposal is the inclusion of native Swift
> enum and struct types in archival and serialization. Currently,
> developers targeting Swift cannot participate in NSCoding without being
> willing to abandon enum and structtypes — NSCoding is an @objc protocol,
> conformance to which excludes non-class types. This is can be limiting in
> Swift because small enums and structs can be an idiomatic approach to
> model representation; developers who wish to perform archival have to
> either forgo the Swift niceties that constructs like enumsprovide, or
> provide an additional compatibility layer between their "real" types and
> their archivable types.
>
> Secondarily, we would like to refine Foundation's existing serialization
> APIs (NSJSONSerialization and NSPropertyListSerialization) to better
> match Swift's strong type safety. From experience, we find that the
> conversion from the unstructured, untyped data of these formats into
> strongly-typed data structures is a good fit for archival mechanisms,
> rather than taking the less safe approach that 3rd-party JSON conversion
> approaches have taken (described further in an appendix below).
>
> We would like to offer a solution to these problems without sacrificing
> ease of use or type safety.
> Agenda
>
> This proposal is the first stage of three that introduce different facets
> of a whole Swift archival and serialization API:
>
>1. This proposal describes the basis for this API, focusing on the
>protocols that users adopt and interface with
>2. The next stage will propose specific API for new encoders
>3. The final stage will discuss how this new API will interop with
>NSCoding as it is today
>
> SE- provides stages 2 and 3.
> Proposed solution
>
> We will be introducing the following new types:
>
>- protocol Codable: Adopted by types to opt into archival. Conformance
>may be automatically derived in cases where all properties are also
>Codable.
>- protocol CodingKey: Adopted by types used as keys for keyed
>containers, replacing String keys with semantic types. Conformance may
>be automatically derived in most cases.
>- protocol Encoder: Adopted by types which can take Codable values and
>encode them into a native 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-21 Thread Brent Royal-Gordon via swift-evolution
> On Mar 20, 2017, at 12:31 PM, Itai Ferber  wrote:
> 
> I don’t think there’s much of a difference between adding an "optional" 
> primitive (which has a default implementation in terms of a different 
> primitive) and simply having that type adopt Codable itself and not be a 
> primitive. You can still switch on the type dynamically (and we do), but you 
> don’t need the optional overload for it.

There's an important exception to that: You can't switch on a protocol which 
has associated types, like BinaryInteger or FloatingPoint.

-- 
Brent Royal-Gordon
Architechies

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-20 Thread Itai Ferber via swift-evolution
I don’t think there’s much of a difference between adding an 
"optional" primitive (which has a default implementation in terms of a 
different primitive) and simply having that type adopt `Codable` itself 
and not be a primitive. You can still switch on the type dynamically 
(and we do), but you don’t need the optional overload for it.


On 19 Mar 2017, at 19:33, Jonathan Hull wrote:

> On Mar 17, 2017, at 1:23 PM, Brent Royal-Gordon via swift-evolution 
 wrote:


(Also, is there any sense in adding `Date` to this set, since it 
needs special treatment in many of our formats?)


We’ve considered adding Date to this list. However, this means 
that any format that is a part of this system needs to be able to 
make a decision about how to format dates. Many binary formats have 
no native representations of dates, so this is not necessarily a 
guarantee that all formats can make.


Looking for additional opinions on this one.

I think that, if you're taking the view that you want to provide a 
set of pre-specified primitive methods as a list of things you want 
encoders to make a policy decision about, Date is a good candidate. 
But as I said earlier, I'd prefer to radically reduce the set of 
primitives, not add to it.


IIUC, two of your three proposed, Foundation-provided coders need to 
do something special with dates; perhaps one of the three needs to do 
something special with different integer sizes and types. Think of 
that as a message about your problem domain.


Have you considered having a very small set of true primitives, and a 
larger set of optional primitives.  For the optional primitives, a 
default implementation would be provided that converts it to/from one 
of the true primitives (e.g. date <—> string), but it would still 
provide an override point for formats that want to support it more 
directly.


Thanks,
Jon



___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-20 Thread Tony Parker via swift-evolution
Hi Kenny,

> On Mar 19, 2017, at 9:53 PM, Kenny Leung via swift-evolution 
>  wrote:
> 
> Hi All.
> 
> Forgive me if I missed it - I haven’t read the proposal in full detail - but 
> it seems to make no mention of archiving graphs with circular references. Is 
> this implicitly supported, or explicitly unsupported?
> 

We expect this to be left up to the encoders and decoders. In Foundation 
itself, we actually have subclasses of NSCoder that support this and subclasses 
that do not.

> While we’re at it, my only real exposure to archiving is through Foundation, 
> so I’d like to know how everybody else understands these terms:
> 
> serialization - the process of “flattening” out an object graph into a serial 
> stream of objects
> 
> encoding - the process of converting internal object data into an external 
> format
> 
> archiving - the whole enchilada of serialization + encoding
> 
> Thanks!
> 
> -Kenny

Good question about terminology. Here is how we’ve tried to define these:

Serialization: conversion of a small fixed set of types to a data format and 
back
ex. NSJSONSerialization, NSPropertyListSerialization

Encoding: conversion of an arbitrary type to a smaller set of serialized types 
and back
ex: Encoder, Decoder, JSONEncoder, PropertyListEncoder

Archiver: In the ObjC Foundation, the objects which do the encoding. In this 
proposal we have chosen not to re-use this term to avoid confusion. Instead we 
tried to simplify the terminology by calling the top level concrete object an 
encoder.

- Tony

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-20 Thread Matthew Johnson via swift-evolution

> On Mar 20, 2017, at 5:34 AM, Brent Royal-Gordon  
> wrote:
> 
>> On Mar 19, 2017, at 8:19 PM, Matthew Johnson > > wrote:
>> 
>> First, your solution does not allow a user to see a context if they can't 
>> name the type (you can't get it as Any and use reflection, etc).
> 
> What I meant is that, if you retrieve the context, you know it is of the type 
> you expect. You don't need to *also* cast it.

Right.  What I’m saying is that if all we’re doing is moving the cast in to the 
encoder / decoder I don’t see value in doing that over the obvious thing of 
exposing the context as Any? and letting the caller cast it.  If the encoder / 
decoder uses the requested type in an algorithm to find the matching context 
then we obviously do need to pass the type as a parameter.  :)

> 
>> I don't see this restriction as being beneficial.  Second, your solution 
>> introduces several subtle problems mentioned in my last email which you 
>> didn't respond to (overlapping context types, etc).  
> 
> I mentioned that, if we give up storing values in a dictionary, we can come 
> up with some sort of sensible-ish behavior for overlapping context types.

Oh, sorry.  I missed that the breadth-first algorithm for finding a matching 
context was the answer to this.

> 
>   protocol Encoder {
>   // Retrieve the context instance of the indicated type.
>   func context(ofType type: Context.Type) -> Context?
>   
>   // This context is visible for `encode(_:)` calls from this 
> encoder's containers all the way down, recursively.
>   func addContext(_ context: Context, ofType type: 
> Context.Type)
 
 What happens if you call `addContext` more than once with values of the 
 same type?
>>> 
>>> It overrides the previous context, but only for the containers created by 
>>> this `encode(to:)` method and any containers nested within them.
>>> 
>>> (Although that could cause trouble for an encoder which only encodes 
>>> objects with multiple instances once. Hmm.)
>>> 
 And why do you require the type to be passed explicitly when it is already 
 implied by the type of the value?
>>> 
>>> As you surmised later, I was thinking in terms of `type` being used as a 
>>> dictionary key; in that case, if you stored a `Foo` into the context, you 
>>> would not later be able to look it up using one of `Foo`'s supertypes. But 
>>> if we really do expect multiple contexts to be rare, perhaps we don't need 
>>> a dictionary at all—we can just keep an array, loop over it with `as?`, and 
>>> return the first (or last?) match. If that's what we do, then we probably 
>>> don't need to pass the type explicitly.
>> 
>> The array approach is better because at least there is an order to the 
>> contexts and we can assign precise semantics in the presence of overlapping 
>> context types by saying type get the first (most recent) context that can be 
>> cast to the type you ask for.  
>> 
>> That said, I think what you're really trying to model here is a context 
>> stack, isn't it?  Why don't we just do that?
> 
> You mention this a couple times, but I don't think it's really possible. 
> Here's why.
> 
> Suppose you write these types:
> 
>   struct SomeObjectContext {
>   var oldFormat: Bool
>   }
>   
>   struct Root: Codeable {
>   var str: SomeStruct
>   var obj: SomeObject
>   
>   func encode(to encoder: Encoder) throws {
>   encoder.push(SomeObjectContext(oldFormat: true))
>   
>   let container = encoder.container(keyedBy: 
> CodingKeys.self)
>   try container.encode(str, forKey: .str)
>   try container.encode(obj, forKey: .obj)
>   }
>   ...
>   }
>   
>   struct SomeStruct: Codeable {
>   var obj: SomeObject
>   
>   func encode(to encoder: Encoder) throws {
>   encoder.push(SomeObjectContext(oldFormat: false))
>   
>   let container = encoder.container(keyedBy: 
> CodingKeys.self)
>   try container.encode(obj, forKey: .obj)
>   }
>   }
>   
>   class SomeObject: Codeable {
>   …
>   
>   func encode(to encoder: Encoder) throws {
>   let context = encoder.context(ofType: 
> SomeObjectContext.self)
>   
>   print(context.oldFormat)
>   …
>   }
>   }
> 
> And you construct an object graph like this:
> 
>   let object = SomeObject()
>   
>   let root = Root(
>   str: SomeStruct(obj: object),
>   obj: object
>   )
> 
> And finally, you encode it with a coder 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-20 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Mar 20, 2017, at 1:43 AM, David Hart  wrote:
> 
> 
>> On 20 Mar 2017, at 02:09, Matthew Johnson via swift-evolution 
>>  wrote:
>> 
>> 
 On Mar 19, 2017, at 2:21 PM, Tony Parker  wrote:
 
 
 On Mar 19, 2017, at 12:14 PM, Matthew Johnson  
 wrote:
 
 
 
 Sent from my iPhone
 
> On Mar 19, 2017, at 10:47 AM, Tony Parker  
> 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.

I agree with this.  That is why I suggested we need to add convenience for the 
single context of a custom type if we go that route.  I like the context stack 
idea I posted later last night better though.  It gets away from the context 
dictionary altogether.

> 
>> 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 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-20 Thread Brent Royal-Gordon via swift-evolution
> On Mar 19, 2017, at 8:19 PM, Matthew Johnson  wrote:
> 
> First, your solution does not allow a user to see a context if they can't 
> name the type (you can't get it as Any and use reflection, etc).

What I meant is that, if you retrieve the context, you know it is of the type 
you expect. You don't need to *also* cast it.

> I don't see this restriction as being beneficial.  Second, your solution 
> introduces several subtle problems mentioned in my last email which you 
> didn't respond to (overlapping context types, etc).  

I mentioned that, if we give up storing values in a dictionary, we can come up 
with some sort of sensible-ish behavior for overlapping context types.

protocol Encoder {
// Retrieve the context instance of the indicated type.
func context(ofType type: Context.Type) -> Context?

// This context is visible for `encode(_:)` calls from this 
 encoder's containers all the way down, recursively.
func addContext(_ context: Context, ofType type: 
 Context.Type)
>>> 
>>> What happens if you call `addContext` more than once with values of the 
>>> same type?
>> 
>> It overrides the previous context, but only for the containers created by 
>> this `encode(to:)` method and any containers nested within them.
>> 
>> (Although that could cause trouble for an encoder which only encodes objects 
>> with multiple instances once. Hmm.)
>> 
>>> And why do you require the type to be passed explicitly when it is already 
>>> implied by the type of the value?
>> 
>> As you surmised later, I was thinking in terms of `type` being used as a 
>> dictionary key; in that case, if you stored a `Foo` into the context, you 
>> would not later be able to look it up using one of `Foo`'s supertypes. But 
>> if we really do expect multiple contexts to be rare, perhaps we don't need a 
>> dictionary at all—we can just keep an array, loop over it with `as?`, and 
>> return the first (or last?) match. If that's what we do, then we probably 
>> don't need to pass the type explicitly.
> 
> The array approach is better because at least there is an order to the 
> contexts and we can assign precise semantics in the presence of overlapping 
> context types by saying type get the first (most recent) context that can be 
> cast to the type you ask for.  
> 
> That said, I think what you're really trying to model here is a context 
> stack, isn't it?  Why don't we just do that?

You mention this a couple times, but I don't think it's really possible. Here's 
why.

Suppose you write these types:

struct SomeObjectContext {
var oldFormat: Bool
}

struct Root: Codeable {
var str: SomeStruct
var obj: SomeObject

func encode(to encoder: Encoder) throws {
encoder.push(SomeObjectContext(oldFormat: true))

let container = encoder.container(keyedBy: 
CodingKeys.self)
try container.encode(str, forKey: .str)
try container.encode(obj, forKey: .obj)
}
...
}

struct SomeStruct: Codeable {
var obj: SomeObject

func encode(to encoder: Encoder) throws {
encoder.push(SomeObjectContext(oldFormat: false))

let container = encoder.container(keyedBy: 
CodingKeys.self)
try container.encode(obj, forKey: .obj)
}
}

class SomeObject: Codeable {
…

func encode(to encoder: Encoder) throws {
let context = encoder.context(ofType: 
SomeObjectContext.self)

print(context.oldFormat)
…
}
}

And you construct an object graph like this:

let object = SomeObject()

let root = Root(
str: SomeStruct(obj: object),
obj: object
)

And finally, you encode it with a coder which respects object identity, so that 
even if a given object appears in several different places in the object graph, 
it only encodes that object once.

Which context does `SomeObject.encode(to:)` see? The one with `oldFormat` or 
the one without? Is there a "first to call wins" rule? Do we think that's 
sustainable?

There are probably a couple of complicated rules we could use to try to cancel 
this out. But by far the easiest is this: The set of contexts is cast in stone 
at the beginning of the encoding process and cannot be altered after the fact. 
And the simplest way I can come up with to do that, while still allowing 
libraries and subsystems to encapsulate their dependencies, is 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-20 Thread Karl Wagner via swift-evolution

> On 17 Mar 2017, at 17:07, Tony Parker  wrote:
> 
> Hi Karl,
> 
>> On Mar 17, 2017, at 12:20 AM, Karl Wagner via swift-evolution 
>> > wrote:
>> 
>> 
>>> On 16 Mar 2017, at 21:48, Slava Pestov via swift-evolution 
>>> > wrote:
>>> 
>>> Hi Itai,
>>> 
>>> I’m wondering what the motivation is for keeping this as part of Foundation 
>>> and not the standard library. It seems like you’re landing an 
>>> implementation of this in the Foundation overlay on master, and another 
>>> copy of all the code will have to go into swift-corelibs-foundation. This 
>>> seems suboptimal. Or are there future plans to unify the Foundation overlay 
>>> with corelibs-foundation somehow?
>>> 
>>> Also the implementation uses some Foundation-isms (NSMutableArray, 
>>> NSNumber) and it would be nice to stick with idiomatic Swift as much as 
>>> possible instead.
>>> 
>>> Finally you should take a look at the integer protocol work 
>>> (https://github.com/apple/swift-evolution/blob/master/proposals/0104-improved-integers.md
>>>  
>>> )
>>>  to replace the repetitive code surrounding primitive types, however I 
>>> don’t know if this has landed in master yet.
>>> 
>>> Slava
>> 
>> I agree that the protocols should be part of the standard library rather 
>> than Foundation. As far as I can make out, the only part of this proposal 
>> that actually requires Foundation is the use of the “Data” type (which 
>> itself is a strange and often frustrating omission from the standard 
>> library). The actual concrete encoders can live in Foundation.
>> 
>> Generally my opinion is that the proposed feature is nice. Everybody hates 
>> NSCoder and having to write those required initialisers on your UIViews and 
>> whatnot. At its core, it’s not really very different from any other Swift 
>> archiving library which exists today, except that it’s backed with layer 
>> upon layer of compiler-generated magic to make it less verbose. The things I 
>> don’t like:
>> 
>> 1) While making things less verbose is commendable, automatically generating 
>> the encoding functions could be an anti-feature. “Codable” is for properties 
>> with persistable values only, which is a level of semantics which goes above 
>> the type-system. We don’t generate Equatable conformance for structs whose 
>> elements are all Equatable; it’s a big leap to go from “this data type is 
>> persistable” to “the value of this variable should be persisted” - for one 
>> thing, the value may not have meaning to others (e.g. a file-handle as an 
>> Int32) or it may contain sensitive user-data in a String. The encoding 
>> function isn’t just boilerplate - you *should* think about it; otherwise who 
>> knows what kind of data you’re leaking?
>> 
>> => One possible solution would be to have “Codable" as a regular protocol, 
>> and refine it with “AutoCodable" which contains the magic. Just so there is 
>> a little extra step where you think “do I want this to be generated?”.
> 
> The number one complaint we have about NSCoding (and this complaint predates 
> Swift by a long shot) is that too much boilerplate is required for really 
> simple data structures. Resolving this issue is one of our primary goals for 
> this API.

Sure, but my point is that even for simple data structures, it’s worth thinking 
about what data you’re making available for persistence. That’s a level of 
semantic understanding which goes beyond the type-system: the compiler can’t 
tell if your String or Int contains per-instance or sensitive data. Also, this 
kind of synthesised behaviour doesn’t happen for any other protocol or library 
- not even for Equatable, which users probably ask for much more frequently 
than serialisation (just guessing).

> 
> There are a lot of benefits to keeping one protocol in place instead of 
> making another one for “auto” codable: API which accepts Codable things does 
> not need to have two entry points; there is one concept of Codable instead of 
> two; you can “buy in” to more complex behavior by implementing parts of 
> Codable (e.g., just the keys if you simply want to change the names of the 
> JSON keys).

They wouldn’t need any new entry-points. AutoCodable would refine Codable; it 
wouldn’t add any requirements, just be an explicit declaration for the compiler 
to synthesise conformance because some data structure is expected to contain 
persistable values. Also, if I’m a programmer, and I see: “struct Foo: 
Codable”, I don’t know if the implementation of Codable exists in an extension 
somewhere (possibly in another file) or not.

> 
>> 
>> 2) More generally, though, I don’t support the idea of the Foundation module 
>> introducing extensions to the Swift language that no other developer of any 
>> other module has the chance to 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-20 Thread David Hart via swift-evolution

> On 20 Mar 2017, at 02:09, Matthew Johnson via swift-evolution 
>  wrote:
> 
> 
>>> On Mar 19, 2017, at 2:21 PM, Tony Parker  wrote:
>>> 
>>> 
>>> On Mar 19, 2017, at 12:14 PM, Matthew Johnson  
>>> wrote:
>>> 
>>> 
>>> 
>>> Sent from my iPhone
>>> 
 On Mar 19, 2017, at 10:47 AM, Tony Parker  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 
>>  wrote:
>> 
>> 
>>> On Mar 17, 2017, at 6:15 PM, Brent Royal-Gordon 
>>>  wrote:
>>> 
 On Mar 17, 2017, at 3:35 PM, Matthew Johnson  
 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 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-19 Thread Kenny Leung via swift-evolution
Hi All.

Forgive me if I missed it - I haven’t read the proposal in full detail - but it 
seems to make no mention of archiving graphs with circular references. Is this 
implicitly supported, or explicitly unsupported?

While we’re at it, my only real exposure to archiving is through Foundation, so 
I’d like to know how everybody else understands these terms:

serialization - the process of “flattening” out an object graph into a serial 
stream of objects

encoding - the process of converting internal object data into an external 
format

archiving - the whole enchilada of serialization + encoding

Thanks!

-Kenny

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-19 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Mar 19, 2017, at 10:19 PM, Matthew Johnson via swift-evolution 
>  wrote:
> 
> 
> 
> Sent from my iPad
> 
>> On Mar 19, 2017, at 9:14 PM, Brent Royal-Gordon  
>> wrote:
>> 
>>> On Mar 19, 2017, at 5:51 PM, Matthew Johnson  wrote:
>>> 
>>> I generally agree with you about casting.  However, my dislike isn’t the 
>>> cast itself, but instead it is the lack of a static guarantee.  I’m not 
>>> sure we’ll find a solution that provides a static guarantee that a required 
>>> context exists that is also acceptable to the Foundation team.
>> 
>> I don't think we can get a static guarantee that the context is present, but 
>> I still would like a static guarantee that the context is of the expected 
>> type. That's what I'm trying to provide here.
> 
> This doesn't do any better job of that than a cast in user code.  I can see 
> two meaningful differences.  First, your solution does not allow a user to 
> see a context if they can't name the type (you can't get it as Any and use 
> reflection, etc).  I don't see this restriction as being beneficial.  Second, 
> your solution introduces several subtle problems mentioned in my last email 
> which you didn't respond to (overlapping context types, etc).  
> 
>> 
 
protocol Encoder {
// Retrieve the context instance of the indicated type.
func context(ofType type: Context.Type) -> Context?

// This context is visible for `encode(_:)` calls from this 
 encoder's containers all the way down, recursively.
func addContext(_ context: Context, ofType type: 
 Context.Type)
>>> 
>>> What happens if you call `addContext` more than once with values of the 
>>> same type?
>> 
>> It overrides the previous context, but only for the containers created by 
>> this `encode(to:)` method and any containers nested within them.
>> 
>> (Although that could cause trouble for an encoder which only encodes objects 
>> with multiple instances once. Hmm.)
>> 
>>> And why do you require the type to be passed explicitly when it is already 
>>> implied by the type of the value?
>> 
>> As you surmised later, I was thinking in terms of `type` being used as a 
>> dictionary key; in that case, if you stored a `Foo` into the context, you 
>> would not later be able to look it up using one of `Foo`'s supertypes. But 
>> if we really do expect multiple contexts to be rare, perhaps we don't need a 
>> dictionary at all—we can just keep an array, loop over it with `as?`, and 
>> return the first (or last?) match. If that's what we do, then we probably 
>> don't need to pass the type explicitly.
> 
> The array approach is better because at least there is an order to the 
> contexts and we can assign precise semantics in the presence of overlapping 
> context types by saying type get the first (most recent) context that can be 
> cast to the type you ask for.  
> 
> That said, I think what you're really trying to model here is a context 
> stack, isn't it?  Why don't we just do that?
> 
>> 
}
// Likewise on Decoder

// Encoder and decoder classes should accept contexts in their 
 top-level API:
open class JSONEncoder {
open func encode(_ value: Value, withContexts 
 contexts: [Any] = []) throws -> Data
}
>>> 
>>> What happens if more than one context of the same type is provided here?
>> 
>> Fail a precondition, probably.
> 
> I would never support this design.  Good news though: the context stack 
> approach avoids the problem.  We allow multiple contexts of the same type to 
> be on the stack and the topmost context that can be cast to the requested 
> type is used.
> 
>> 
>>> Also, it’s worth pointing out that whatever reason you had for explicitly 
>>> passing the type above you’re not requiring type information to be provided 
>>> here.  Whatever design we have it should be self-consistent.
>> 
>> Yeah. I did this here because there was no way to specify a dictionary 
>> literal of `(T.Type, T)`, where `T` could be different for different 
>> elements.
>> 
>>> Do you think it’s really important to allow users to dynamically provide 
>>> context for children?  Do you have real world use cases where this is 
>>> needed?  I’m sure there could be case where this might be useful.  But I 
>>> also think there is some benefit in knowing that the context used for an 
>>> entire encoding / decoding is the one you provide at the top level.  I 
>>> suspect the benefit of a static guarantee that your context is used for the 
>>> entire encoding / decoding has a lot more value than the ability to 
>>> dynamically change the context for a subtree.
>> 
>> The problem with providing all the contexts at the top level is that then 
>> the top level has to *know* what all the contexts needed are. Again, if 
>> you're encoding a type from FooKit, and it 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-19 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Mar 19, 2017, at 9:14 PM, Brent Royal-Gordon  
> wrote:
> 
>> On Mar 19, 2017, at 5:51 PM, Matthew Johnson  wrote:
>> 
>> I generally agree with you about casting.  However, my dislike isn’t the 
>> cast itself, but instead it is the lack of a static guarantee.  I’m not sure 
>> we’ll find a solution that provides a static guarantee that a required 
>> context exists that is also acceptable to the Foundation team.
> 
> I don't think we can get a static guarantee that the context is present, but 
> I still would like a static guarantee that the context is of the expected 
> type. That's what I'm trying to provide here.

This doesn't do any better job of that than a cast in user code.  I can see two 
meaningful differences.  First, your solution does not allow a user to see a 
context if they can't name the type (you can't get it as Any and use 
reflection, etc).  I don't see this restriction as being beneficial.  Second, 
your solution introduces several subtle problems mentioned in my last email 
which you didn't respond to (overlapping context types, etc).  

> 
>>> 
>>> protocol Encoder {
>>> // Retrieve the context instance of the indicated type.
>>> func context(ofType type: Context.Type) -> Context?
>>> 
>>> // This context is visible for `encode(_:)` calls from this 
>>> encoder's containers all the way down, recursively.
>>> func addContext(_ context: Context, ofType type: 
>>> Context.Type)
>> 
>> What happens if you call `addContext` more than once with values of the same 
>> type?
> 
> It overrides the previous context, but only for the containers created by 
> this `encode(to:)` method and any containers nested within them.
> 
> (Although that could cause trouble for an encoder which only encodes objects 
> with multiple instances once. Hmm.)
> 
>> And why do you require the type to be passed explicitly when it is already 
>> implied by the type of the value?
> 
> As you surmised later, I was thinking in terms of `type` being used as a 
> dictionary key; in that case, if you stored a `Foo` into the context, you 
> would not later be able to look it up using one of `Foo`'s supertypes. But if 
> we really do expect multiple contexts to be rare, perhaps we don't need a 
> dictionary at all—we can just keep an array, loop over it with `as?`, and 
> return the first (or last?) match. If that's what we do, then we probably 
> don't need to pass the type explicitly.

The array approach is better because at least there is an order to the contexts 
and we can assign precise semantics in the presence of overlapping context 
types by saying type get the first (most recent) context that can be cast to 
the type you ask for.  

That said, I think what you're really trying to model here is a context stack, 
isn't it?  Why don't we just do that?

> 
>>> }
>>> // Likewise on Decoder
>>> 
>>> // Encoder and decoder classes should accept contexts in their 
>>> top-level API:
>>> open class JSONEncoder {
>>> open func encode(_ value: Value, withContexts 
>>> contexts: [Any] = []) throws -> Data
>>> }
>> 
>> What happens if more than one context of the same type is provided here?
> 
> Fail a precondition, probably.

I would never support this design.  Good news though: the context stack 
approach avoids the problem.  We allow multiple contexts of the same type to be 
on the stack and the topmost context that can be cast to the requested type is 
used.

> 
>> Also, it’s worth pointing out that whatever reason you had for explicitly 
>> passing the type above you’re not requiring type information to be provided 
>> here.  Whatever design we have it should be self-consistent.
> 
> Yeah. I did this here because there was no way to specify a dictionary 
> literal of `(T.Type, T)`, where `T` could be different for different elements.
> 
>> Do you think it’s really important to allow users to dynamically provide 
>> context for children?  Do you have real world use cases where this is 
>> needed?  I’m sure there could be case where this might be useful.  But I 
>> also think there is some benefit in knowing that the context used for an 
>> entire encoding / decoding is the one you provide at the top level.  I 
>> suspect the benefit of a static guarantee that your context is used for the 
>> entire encoding / decoding has a lot more value than the ability to 
>> dynamically change the context for a subtree.
> 
> The problem with providing all the contexts at the top level is that then the 
> top level has to *know* what all the contexts needed are. Again, if you're 
> encoding a type from FooKit, and it uses a type from GeoKit, then you—the 
> user of FooKit—need to know that FooKit uses GeoKit and how to make contexts 
> for both of them. There's no way to encapsulate GeoKit's role in encoding.

The use cases I know of for contexts are really around 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-19 Thread Jonathan Hull via swift-evolution

> On Mar 17, 2017, at 1:23 PM, Brent Royal-Gordon via swift-evolution 
>  wrote:
> 
>> (Also, is there any sense in adding `Date` to this set, since it needs 
>> special treatment in many of our formats?)
>> 
>> We’ve considered adding Date to this list. However, this means that any 
>> format that is a part of this system needs to be able to make a decision 
>> about how to format dates. Many binary formats have no native 
>> representations of dates, so this is not necessarily a guarantee that all 
>> formats can make.
>> 
>> Looking for additional opinions on this one.
>> 
> I think that, if you're taking the view that you want to provide a set of 
> pre-specified primitive methods as a list of things you want encoders to make 
> a policy decision about, Date is a good candidate. But as I said earlier, I'd 
> prefer to radically reduce the set of primitives, not add to it.
> 
> IIUC, two of your three proposed, Foundation-provided coders need to do 
> something special with dates; perhaps one of the three needs to do something 
> special with different integer sizes and types. Think of that as a message 
> about your problem domain.

Have you considered having a very small set of true primitives, and a larger 
set of optional primitives.  For the optional primitives, a default 
implementation would be provided that converts it to/from one of the true 
primitives (e.g. date <—> string), but it would still provide an override point 
for formats that want to support it more directly.

Thanks,
Jon___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-19 Thread Brent Royal-Gordon via swift-evolution
> On Mar 19, 2017, at 5:51 PM, Matthew Johnson  wrote:
> 
> I generally agree with you about casting.  However, my dislike isn’t the cast 
> itself, but instead it is the lack of a static guarantee.  I’m not sure we’ll 
> find a solution that provides a static guarantee that a required context 
> exists that is also acceptable to the Foundation team.

I don't think we can get a static guarantee that the context is present, but I 
still would like a static guarantee that the context is of the expected type. 
That's what I'm trying to provide here.

>> 
>>  protocol Encoder {
>>  // Retrieve the context instance of the indicated type.
>>  func context(ofType type: Context.Type) -> Context?
>>  
>>  // This context is visible for `encode(_:)` calls from this 
>> encoder's containers all the way down, recursively.
>>  func addContext(_ context: Context, ofType type: 
>> Context.Type)
> 
> What happens if you call `addContext` more than once with values of the same 
> type?

It overrides the previous context, but only for the containers created by this 
`encode(to:)` method and any containers nested within them.

(Although that could cause trouble for an encoder which only encodes objects 
with multiple instances once. Hmm.)

> And why do you require the type to be passed explicitly when it is already 
> implied by the type of the value?

As you surmised later, I was thinking in terms of `type` being used as a 
dictionary key; in that case, if you stored a `Foo` into the context, you would 
not later be able to look it up using one of `Foo`'s supertypes. But if we 
really do expect multiple contexts to be rare, perhaps we don't need a 
dictionary at all—we can just keep an array, loop over it with `as?`, and 
return the first (or last?) match. If that's what we do, then we probably don't 
need to pass the type explicitly.

>>  }
>>  // Likewise on Decoder
>>  
>>  // Encoder and decoder classes should accept contexts in their 
>> top-level API:
>>  open class JSONEncoder {
>>  open func encode(_ value: Value, withContexts 
>> contexts: [Any] = []) throws -> Data
>>  }
> 
> What happens if more than one context of the same type is provided here?

Fail a precondition, probably.

> Also, it’s worth pointing out that whatever reason you had for explicitly 
> passing the type above you’re not requiring type information to be provided 
> here.  Whatever design we have it should be self-consistent.

Yeah. I did this here because there was no way to specify a dictionary literal 
of `(T.Type, T)`, where `T` could be different for different elements.

> Do you think it’s really important to allow users to dynamically provide 
> context for children?  Do you have real world use cases where this is needed? 
>  I’m sure there could be case where this might be useful.  But I also think 
> there is some benefit in knowing that the context used for an entire encoding 
> / decoding is the one you provide at the top level.  I suspect the benefit of 
> a static guarantee that your context is used for the entire encoding / 
> decoding has a lot more value than the ability to dynamically change the 
> context for a subtree.

The problem with providing all the contexts at the top level is that then the 
top level has to *know* what all the contexts needed are. Again, if you're 
encoding a type from FooKit, and it uses a type from GeoKit, then you—the user 
of FooKit—need to know that FooKit uses GeoKit and how to make contexts for 
both of them. There's no way to encapsulate GeoKit's role in encoding.

On the other hand, there *could* be a way to encapsulate it. Suppose we had a 
context protocol:

protocol CodingContext {
var underlyingContexts: [CodingContext] { get }
}
extension CodingContext {
var underlyingContexts: [CodingContext] { return [] }
}

Then you could have this as your API surface:

protocol Encoder {
// Retrieve the context instance of the indicated type.
func context(ofType type: Context.Type) 
-> Context?
}
// Likewise on Decoder

// Encoder and decoder classes should accept contexts in their 
top-level API:
open class JSONEncoder {
open func encode(_ value: Value, with context: 
CodingContext? = nil) throws -> Data
}

And libraries would be able to add additional contexts for dependencies as 
needed.

(Hmm. Could we maybe do this?

protocol Codable {
associatedtype CodingContextType: CodingContext = Never

func encode(to encoder: Encoder) throws
init(from decoder: Decoder) throws
}

protocol Encoder {
// Retrieve the context instance of the indicated type.
func context(for instance: Codable) -> 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-19 Thread Matthew Johnson via swift-evolution

> On Mar 19, 2017, at 2:21 PM, Tony Parker  wrote:
> 
> 
>> On Mar 19, 2017, at 12:14 PM, Matthew Johnson > > wrote:
>> 
>> 
>> 
>> Sent from my iPhone
>> 
>> On Mar 19, 2017, at 10:47 AM, Tony Parker > > 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.

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 
 > wrote:
 
> 
> On Mar 17, 2017, at 6:15 PM, Brent Royal-Gordon  > wrote:
> 
>> On Mar 17, 2017, at 3:35 PM, Matthew Johnson > > 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 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-19 Thread Matthew Johnson via swift-evolution

> On Mar 19, 2017, at 3:38 PM, Brent Royal-Gordon  
> wrote:
> 
>> On Mar 19, 2017, at 12:21 PM, Tony Parker > > wrote:
>>> 
>>> On Mar 19, 2017, at 12:14 PM, Matthew Johnson >> > wrote:
>>> 
>>> On Mar 19, 2017, at 10:47 AM, Tony Parker >> > 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].
> 
> I hate casting out of Any, and I strongly believe we should support multiple 
> contexts, so personally, I'd prefer something typed:

I can imagine multiple contexts being useful in rare cases; much more rarely 
than a single context but still worth supporting.

I generally agree with you about casting.  However, my dislike isn’t the cast 
itself, but instead it is the lack of a static guarantee.  I’m not sure we’ll 
find a solution that provides a static guarantee that a required context exists 
that is also acceptable to the Foundation team.

> 
>   protocol Encoder {
>   // Retrieve the context instance of the indicated type.
>   func context(ofType type: Context.Type) -> Context?
>   
>   // This context is visible for `encode(_:)` calls from this 
> encoder's containers all the way down, recursively.
>   func addContext(_ context: Context, ofType type: 
> Context.Type)

What happens if you call `addContext` more than once with values of the same 
type?  And why do you require the type to be passed explicitly when it is 
already implied by the type of the value?

>   }
>   // Likewise on Decoder
>   
>   // Encoder and decoder classes should accept contexts in their 
> top-level API:
>   open class JSONEncoder {
>   open func encode(_ value: Value, withContexts 
> contexts: [Any] = []) throws -> Data
>   }

What happens if more than one context of the same type is provided here?  Also, 
it’s worth pointing out that whatever reason you had for explicitly passing the 
type above you’re not requiring type information to be provided here.  Whatever 
design we have it should be self-consistent.

I’m going to speculate that the intent above is that the types of the context 
values are treated as a key into a dictionary, or something along those lines.  
I’ll also speculate that if more than one context of the same type exist are 
provided at a given stack level level the latest one overwrites the previous 
one (what else would happen - `addContext` is non-throwing).

Do you think it’s really important to allow users to dynamically provide 
context for children?  Do you have real world use cases where this is needed?  
I’m sure there could be case where this might be useful.  But I also think 
there is some benefit in knowing that the context used for an entire encoding / 
decoding is the one you 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-19 Thread Brent Royal-Gordon via swift-evolution
> On Mar 19, 2017, at 12:21 PM, Tony Parker  wrote:
>> 
>> On Mar 19, 2017, at 12:14 PM, Matthew Johnson > > wrote:
>> 
>> On Mar 19, 2017, at 10:47 AM, Tony Parker > > 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].

I hate casting out of Any, and I strongly believe we should support multiple 
contexts, so personally, I'd prefer something typed:

protocol Encoder {
// Retrieve the context instance of the indicated type.
func context(ofType type: Context.Type) -> Context?

// This context is visible for `encode(_:)` calls from this 
encoder's containers all the way down, recursively.
func addContext(_ context: Context, ofType type: 
Context.Type)
}
// Likewise on Decoder

// Encoder and decoder classes should accept contexts in their 
top-level API:
open class JSONEncoder {
open func encode(_ value: Value, withContexts 
contexts: [Any] = []) throws -> Data
}

-- 
Brent Royal-Gordon
Architechies

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-19 Thread Tony Parker via swift-evolution

> On Mar 19, 2017, at 12:14 PM, Matthew Johnson  wrote:
> 
> 
> 
> Sent from my iPhone
> 
> On Mar 19, 2017, at 10:47 AM, Tony Parker  > 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].

- Tony

> 
>> 
>> - Tony
>> 
>>> On Mar 17, 2017, at 5:56 PM, Matthew Johnson via swift-evolution 
>>> > wrote:
>>> 
 
 On Mar 17, 2017, at 6:15 PM, Brent Royal-Gordon > wrote:
 
> On Mar 17, 2017, at 3:35 PM, Matthew Johnson  > 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 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-19 Thread Matthew Johnson via swift-evolution


Sent from my iPhone

> On Mar 19, 2017, at 10:47 AM, Tony Parker  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.  :)

> 
> - Tony
> 
>>> On Mar 17, 2017, at 5:56 PM, Matthew Johnson via swift-evolution 
>>>  wrote:
>>> 
>>> 
 On Mar 17, 2017, at 6:15 PM, Brent Royal-Gordon  
 wrote:
 
> On Mar 17, 2017, at 3:35 PM, Matthew Johnson  
> 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 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-19 Thread Tony Parker via swift-evolution
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.

- Tony

> On Mar 17, 2017, at 5:56 PM, Matthew Johnson via swift-evolution 
>  wrote:
> 
>> 
>> On Mar 17, 2017, at 6:15 PM, Brent Royal-Gordon > > wrote:
>> 
>>> On Mar 17, 2017, at 3:35 PM, Matthew Johnson >> > 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
> swift-evolution@swift.org 
> https://lists.swift.org/mailman/listinfo/swift-evolution 
> 
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-17 Thread Matthew Johnson via swift-evolution

> On Mar 17, 2017, at 6:15 PM, Brent Royal-Gordon  
> wrote:
> 
>> On Mar 17, 2017, at 3:35 PM, Matthew Johnson > > 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
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-17 Thread T.J. Usiyan via swift-evolution
This does work and can be the solution, I suppose,  but I was thinking
about agreeing upon some convention that could actually make it into the
protocols or–at the least–documentation. As it is, the problem creeps up on
newcomers and isn't so obvious until you actually have a second version of
your format.

On Fri, Mar 17, 2017 at 3:47 PM, Itai Ferber  wrote:

> Do you mean versions of the format, or versions of your type?
>
> If the latter, this can be done on a case-by-case basis, as needed. You
> can always do something like
>
> struct Foo : Codable {
> // Name this as appropriate
> private let jsonVersion = 1.1
> }
>
> and have it encode as well.
>
> On 17 Mar 2017, at 11:51, T.J. Usiyan wrote:
>
> Is there any sense of encoding versions (as in, changes to the JSON
> representation, for instance?) I don't know that it is necessarily a good
> idea overall but now is the time to consider it.
>
> On Fri, Mar 17, 2017 at 2:27 PM, Matthew Johnson via swift-evolution <
> swift-evolution@swift.org> wrote:
>
>>
>> On Mar 17, 2017, at 1:15 PM, Itai Ferber via swift-evolution <
>> swift-evolution@swift.org> wrote:
>>
>> On 15 Mar 2017, at 22:58, Zach Waldowski wrote:
>>
>> Another issue of scale - I had to switch to a native mail client as
>> replying inline severely broke my webmail client. ;-)
>>
>> Again, lots of love here. Responses inline.
>>
>> On Mar 15, 2017, at 6:40 PM, Itai Ferber via swift-evolution <
>> swift-evolution@swift.org> wrote:
>> Proposed solution
>> We will be introducing the following new types:
>>
>> protocol Codable: Adopted by types to opt into archival. Conformance may
>> be automatically derived in cases where all properties are also Codable.
>>
>> FWIW I think this is acceptable compromise. If the happy path is derived
>> conformances, only-decodable or only-encodable types feel like a lazy way
>> out on the part of a user of the API, and builds a barrier to proper
>> testing.
>>
>> [snip]
>>
>> Structured types (i.e. types which encode as a collection of properties)
>> encode and decode their properties in a keyed manner. Keys may be
>> String-convertible or Int-convertible (or both), and user types which have
>> properties should declare semantic key enums which map keys to their
>> properties. Keys must conform to the CodingKey protocol:
>> public protocol CodingKey { <##snip##> }
>>
>> A few things here:
>>
>> The protocol leaves open the possibility of having both a String or Int
>> representation, or neither. What should a coder do in either case? Are the
>> representations intended to be mutually exclusive, or not? The protocol
>> design doesn’t seem particularly matching with the flavor of Swift; I’d
>> expect something along the lines of a CodingKey enum and the protocol
>> CodingKeyRepresentable. It’s also possible that the concerns of the two are
>> orthogonal enough that they deserve separate container(keyedBy:)
>> requirements.
>>
>> The general answer to "what should a coder do" is "what is appropriate
>> for its format". For a format that uses exclusively string keys (like
>> JSON), the string representation (if present on a key) will always be used.
>> If the key has no string representation but does have an integer
>> representation, the encoder may choose to stringify the integer. If the key
>> has neither, it is appropriate for the Encoder to fail in some way.
>>
>> On the flip side, for totally flat formats, an Encoder may choose to
>> ignore keys altogether, in which case it doesn’t really matter. The choice
>> is up to the Encoder and its format.
>>
>> The string and integer representations are not meant to be mutually
>> exclusive at all, and in fact, where relevant, we encourage providing both
>> types of representations for flexibility.
>>
>> As for the possibility of having neither representation, this question
>> comes up often. I’d like to summarize the thought process here by quoting
>> some earlier review (apologies for the poor formatting from my mail client):
>>
>> If there are two options, each of which is itself optional, we have 4
>> possible combinations. But! At the same time we prohibit one combination by
>> what? Runtime error? Why not use a 3-case enum for it? Even further down
>> the rabbit whole there might be a CodingKey<> specialized for a concrete
>> combination, like CodingKey or just CodingKey,
>> but I’m not sure whether our type system will make it useful or possible…
>>
>> public enum CodingKeyValue {
>> case integer(value: Int)
>> case string(value: String)
>> case both(intValue: Int, stringValue: String)
>> }
>> public protocol CodingKey {
>> init?(value: CodingKeyValue)
>> var value: CodingKeyValue { get }
>> }
>>
>> I agree that this certainly feels suboptimal. We’ve certainly explored
>> other possibilities before sticking to this one, so let me try to summarize
>> here:
>>
>> * Having a concrete 3-case CodingKey enum would preclude the possibility
>> of having neither a stringValue nor an intValue. 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-17 Thread Brent Royal-Gordon via swift-evolution
> On Mar 17, 2017, at 3:35 PM, Matthew Johnson  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. 
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.

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.

-- 
Brent Royal-Gordon
Architechies

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-17 Thread Matthew Johnson via swift-evolution

> On Mar 17, 2017, at 5:13 PM, Brent Royal-Gordon  
> wrote:
> 
>> On Mar 17, 2017, at 2:38 PM, Matthew Johnson > > wrote:
>> 
>>> At a broad level, that's a good idea. But why not provide something more 
>>> precise than a bag of `Any`s here? You're in pure Swift; you have that 
>>> flexibility.
>>> 
>>> protocol Codable {
>>> associatedtype CodingContext = ()
>>> 
>>> init(from decoder: Coder, with context: 
>>> CodingContext) throws
>>> func encoder(from encoder: Coder, with context: 
>>> CodingContext) throws
>>> }
>>> protocol Encoder {
>>> associatedtype CodingContext = ()
>>> 
>>> func container(keyedBy type: Key.Type) -> 
>>> KeyedEncodingContainer
>>> …
>>> }
>>> class KeyedEncodingContainer {
>>> func encode(_ value: Value,? forKey key: Key, 
>>> with context: Value.CodingContext) throws { … }
>>> 
>>> // Shorthand when contexts are the same:
>>> func encode(_ value: Value,? forKey key: Key) 
>>> throws
>>> where Value.CodingContext == CodingContext
>>> { … }
>>> 
>>> …
>>> }
>> 
>> This is sort of similar to the design I suggested for contexts.  The 
>> difference is that you’re requiring all Codable to be context aware and by 
>> introducing an associated type you break the ability to use Codable as an 
>> existential.
> 
> I don't think banning existentials is actually a loss. Since `encode(_:)` 
> doesn't record type information, and instead `decode(_:)` requires the exact 
> concrete type to be passed in, `Codable` existentials cannot be usefully 
> encoded or decoded. For instance, a heterogeneous `[Codable]` would encode in 
> several different, probably mutually incompatible formats, without any type 
> information that could distinguish between them. Since the only semantics of 
> `Codable` are encoding and decoding, and decoding is always done by an 
> `init`, `Codable` existentials are useless and we lose nothing by not 
> supporting them.

That’s fair.  But how would you change the design of the NSKeyedArchiver / 
NSKeyedUnarchiver extensions which use the existentials? 

> 
>> Many Codable conforming types won’t need to know anything about a context.  
>> I would still want to be able to encode them along with my custom 
>> context-aware types.  A good example is types from Foundation that will 
>> conform to Codable.  They will definitely not know anything about my context 
>> but I still want to be able to encode a URL alongside my custom 
>> context-aware types.
> 
> Sure; you can do that by calling `encode(_:forKey:with:)` and passing a 
> freshly-made `()` context. We might even add a second convenience overload of 
> `encode(_:forKey:)`:
> 
>   class KeyedEncodingContainer {
>   func encode(_ value: Value,? forKey key: Key, 
> with context: Value.CodingContext) throws { … }
>   
>   // Shorthand when contexts are the same:
>   func encode(_ value: Value,? forKey key: Key) 
> throws
>   where Value.CodingContext == CodingContext
>   {
>   try encode(value, forKey: key, with: currentContext)
>   }
>   
>   // Shorthand when the type uses a Void context:
>   func encode(_ value: Value,? forKey key: Key) 
> throws
>   where Value.CodingContext == Void
>   {
>   try encode(value, forKey: key, with: ())
>   }
>   
>   …
>   }
> 
> The main disadvantage I can think of in this design is that even `Codable` 
> users who don't need a context have to have a `with context: Void` in their 
> code. This might be confusing to new developers, but I think it's worth it.
> 
> (I don't think I mentioned this anywhere, but containers like `Array` should 
> take on the `CodingContext` of their `Element`s and pass the context they 
> receive through without examining it. That would probably be pretty common 
> with generic container types.)

You’re right - I just wasn’t thinking about this clearly.  I missed that you 
were requiring Codable types to manually thread the context through.  This is 
kind of unfortunate when *all* types involved in the encoding either have a 
Void context or use the same context type.  On the other hand, it is a somewhat 
rarely needed feature and this approach offers a lot of flexibility.  I think I 
like it.

> 
>> Did you take a look at the design I suggested?  What do you think of it?
> 
> I think that, if a type wants to support context-free coding, it should use 
> an optional `CodingContext`. :^)
> 
> In all seriousness, I see the design as very slightly weak, in that it makes 
> it easy to forget to 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-17 Thread Brent Royal-Gordon via swift-evolution
> On Mar 17, 2017, at 2:38 PM, Matthew Johnson  wrote:
> 
>> At a broad level, that's a good idea. But why not provide something more 
>> precise than a bag of `Any`s here? You're in pure Swift; you have that 
>> flexibility.
>> 
>>  protocol Codable {
>>  associatedtype CodingContext = ()
>>  
>>  init(from decoder: Coder, with context: 
>> CodingContext) throws
>>  func encoder(from encoder: Coder, with context: 
>> CodingContext) throws
>>  }
>>  protocol Encoder {
>>  associatedtype CodingContext = ()
>>  
>>  func container(keyedBy type: Key.Type) -> 
>> KeyedEncodingContainer
>>  …
>>  }
>>  class KeyedEncodingContainer {
>>  func encode(_ value: Value,? forKey key: Key, 
>> with context: Value.CodingContext) throws { … }
>>  
>>  // Shorthand when contexts are the same:
>>  func encode(_ value: Value,? forKey key: Key) 
>> throws
>>  where Value.CodingContext == CodingContext
>>  { … }
>>  
>>  …
>>  }
> 
> This is sort of similar to the design I suggested for contexts.  The 
> difference is that you’re requiring all Codable to be context aware and by 
> introducing an associated type you break the ability to use Codable as an 
> existential.

I don't think banning existentials is actually a loss. Since `encode(_:)` 
doesn't record type information, and instead `decode(_:)` requires the exact 
concrete type to be passed in, `Codable` existentials cannot be usefully 
encoded or decoded. For instance, a heterogeneous `[Codable]` would encode in 
several different, probably mutually incompatible formats, without any type 
information that could distinguish between them. Since the only semantics of 
`Codable` are encoding and decoding, and decoding is always done by an `init`, 
`Codable` existentials are useless and we lose nothing by not supporting them.

> Many Codable conforming types won’t need to know anything about a context.  I 
> would still want to be able to encode them along with my custom context-aware 
> types.  A good example is types from Foundation that will conform to Codable. 
>  They will definitely not know anything about my context but I still want to 
> be able to encode a URL alongside my custom context-aware types.

Sure; you can do that by calling `encode(_:forKey:with:)` and passing a 
freshly-made `()` context. We might even add a second convenience overload of 
`encode(_:forKey:)`:

class KeyedEncodingContainer {
func encode(_ value: Value,? forKey key: Key, 
with context: Value.CodingContext) throws { … }

// Shorthand when contexts are the same:
func encode(_ value: Value,? forKey key: Key) 
throws
where Value.CodingContext == CodingContext
{
try encode(value, forKey: key, with: currentContext)
}

// Shorthand when the type uses a Void context:
func encode(_ value: Value,? forKey key: Key) 
throws
where Value.CodingContext == Void
{
try encode(value, forKey: key, with: ())
}

…
}

The main disadvantage I can think of in this design is that even `Codable` 
users who don't need a context have to have a `with context: Void` in their 
code. This might be confusing to new developers, but I think it's worth it.

(I don't think I mentioned this anywhere, but containers like `Array` should 
take on the `CodingContext` of their `Element`s and pass the context they 
receive through without examining it. That would probably be pretty common with 
generic container types.)

> Did you take a look at the design I suggested?  What do you think of it?

I think that, if a type wants to support context-free coding, it should use an 
optional `CodingContext`. :^)

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. It would 
certainly solve the `with context: Void` problem I mentioned. I might consider 
reversing the relationship between the two protocols, though:

public protocol ContextAwareCodable {
associatedtype CodingContext

init(from decoder: Decoder, with context: CodingContext) throws
func encode(to encoder: Encoder, with context: CodingContext) 
throws
}
public protocol Codable: ContextAwareCodable where CodingContext == 
Void {
init(from decoder: Decoder) throws
func encode(to encoder: Encoder) throws
}
extension Codable {
public init(from decoder: Decoder, with 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-17 Thread Matthew Johnson via swift-evolution


Sent from my iPhone

> On Mar 17, 2017, at 3:36 PM, Joe Groff via swift-evolution 
>  wrote:
> 
> 
>> On Mar 17, 2017, at 12:49 PM, Itai Ferber  wrote:
>> 
>> On 17 Mar 2017, at 12:18, Michael Gottesman wrote:
>> 
>> 
>> On Mar 16, 2017, at 10:23 AM, Joe Groff via swift-evolution 
>>  wrote:
>> 
>> On Mar 16, 2017, at 10:21 AM, Itai Ferber  wrote:
>> 
>> On 15 Mar 2017, at 19:12, Joe Groff wrote:
>> 
>> 
>> On Mar 15, 2017, at 6:46 PM, Itai Ferber  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 { ... }, 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(_ type: Key.Type) -> Cont 
>> where Cont.Key == Key {
>> // return something
>> }
>> 
>> This looks promising so far — let's try to make it concrete:
>> 
>> struct ConcreteContainer : Container {
>> typealias Key = K
>> }
>> 
>> func container(_ type: Key.Type) -> Cont 
>> where Cont.Key == Key {
>> return ConcreteContainer() // error: Cannot convert return expression 
>> of type 'ConcreteContainer' 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() 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
>> 
>> 
> 
> You can implement an AnyContainer type that conforms to the Container 
> protocol, using an abstract base class that erases the type, and a 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-17 Thread Matthew Johnson via swift-evolution

> On Mar 17, 2017, at 3:23 PM, Brent Royal-Gordon via swift-evolution 
>  wrote:
> 
>> On Mar 16, 2017, at 12:33 PM, Itai Ferber > > wrote:
>> Optional values are accepted and vended directly through the API. The 
>> encode(_:forKey:) methods take optional values directly, and 
>> decodeIfPresent(_:forKey:) vend optional values.
>> 
>> Optional is special in this way — it’s a primitive part of the system. It’s 
>> actually not possible to write an encode(to:) method for Optional, since the 
>> representation of null values is up to the encoder and the format it’s 
>> working in; JSONEncoder, for instance, decides on the representation of nil 
>> (JSON null).
>> 
> Yes—I noticed that later but then forgot to revise the beginning. Sorry about 
> that.
>> It wouldn’t be possible to ask nil to encode itself in a reasonable way.
>> 
> I really think it could be done, at least for most coders. I talked about 
> this in another email, but in summary:
> 
> NSNull would become a primitive type; depending on the format, it would be 
> encoded either as a null value or the absence of a value.
> Optional.some(x) would be encoded the same as x.
> Optional.none would be encoded in the following fashion:
> If the Wrapped associated type was itself an optional type, it would be 
> encoded as a keyed container containing a single entry. That entry's key 
> would be some likely-unique value like "_swiftOptionalDepth"; its value would 
> be the number of levels of optionality before reaching a non-optional type.
> If the Wrapped associated type was non-optional, it would be encoded as an 
> NSNull.
> 
> That sounds complicated, but the runtime already has machinery to coerce 
> Optionals to Objective-C id: Optional.some gets bridged as the Wrapped value, 
> while Optional.none gets bridged as either NSNull or _SwiftNull, which 
> contains a depth. We would simply need to make _SwiftNull conform to Codable, 
> and give it a decoding implementation which was clever enough to realize when 
> it was being asked to decode a different type.
>> What about a more complex enum, like the standard library's 
>> `UnicodeDecodingResult`:
>> 
>> enum UnicodeDecodingResult {
>> case emptyInput
>> case error
>> case scalarValue(UnicodeScalar)
>> }
>> 
>> Or, say, an `Error`-conforming type from one of my projects:
>> 
>> public enum SQLError: Error {
>> case connectionFailed(underlying: Error)
>> case executionFailed(underlying: Error, statement: SQLStatement)
>> case noRecordsFound(statement: SQLStatement)
>> case extraRecordsFound(statement: SQLStatement)
>> case columnInvalid(underlying: Error, key: ColumnSpecifier, statement: 
>> SQLStatement)
>> case valueInvalid(underlying: Error, key: AnySQLColumnKey, statement: 
>> SQLStatement)
>> }
>> 
>> (You can assume that all the types in the associated values are `Codable`.)
>> 
>> Sure — these cases specifically do not derive Codable conformance because 
>> the specific representation to choose is up to you. Two possible ways to 
>> write this, though there are many others (I’m simplifying these cases here a 
>> bit, but you can extrapolate this):
>> 
> Okay, so tl;dr is "There's nothing special to help with this; just encode 
> some indication of the case in one key, and the associated values in separate 
> keys". I suppose that works.
>> Have you given any consideration to supporting types which only need to 
>> decode? That seems likely to be common when interacting with web services.
>> 
>> We have. Ultimately, we decided that the introduction of several protocols 
>> to cover encodability, decodability, and both was too much of a cognitive 
>> overhead, considering the number of other types we’re also introducing. You 
>> can always implement encode(to:) as fatalError().
>> 
> I understand that impulse.
>> Structured types (i.e. types which encode as a collection of properties) 
>> encode and decode their properties in a keyed manner. Keys may be 
>> String-convertible or Int-convertible (or both),
>> 
>> What does "may" mean here? That, at runtime, the encoder will test for the 
>> preferred key type and fall back to the other one? That seems a little bit 
>> problematic.
>> 
>> Yes, this is the case. A lot is left up to the Encoder because it can choose 
>> to do something for its format that your implementation of encode(to:) may 
>> not have considered.
>> If you try to encode something with an Int key in a string-keyed dictionary, 
>> the encoder may choose to stringify the integer if appropriate for the 
>> format. If not, it can reject your key, ignore the call altogether, 
>> preconditionFailure(), etc. It is also perfectly legitimate to write an 
>> Encoder which supports a flat encoding format — in that case, keys are 
>> likely ignored altogether, in which case there is no error to be had. We’d 
>> like to not arbitrarily constrain an implementation unless necessary.
>> 
> Wait, what? If it's ignoring 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-17 Thread Matthew Johnson via swift-evolution

> On Mar 17, 2017, at 2:42 PM, Itai Ferber  wrote:
> 
> On 16 Mar 2017, at 14:29, Matthew Johnson wrote:
> 
> 
> This is a fantastic proposal! I am very much looking forward to robust 
> Swift-native encoding and decoding in Foundation. The compiler synthesized 
> conformances is especially great! I want to thank everyone who worked on it. 
> It is clear that a lot of work went into the proposal.
> 
> The proposal covers a lot of ground so I’m breaking my comments up by topic 
> in the order the occur in the proposal.
> 
> Thanks for the feedback, Matthew! Responses inline.
> 
> 

And thank you for the responses!

> 
> Encode / Decode only types:
> 
> Brent raised the question of decode only types. Encode only types are also 
> not uncommon when an API accepts an argument payload that gets serialized 
> into the body of a request. The compiler synthesis feature in the proposal 
> makes providing both encoding and decoding easy in common cases but this 
> won’t always work as needed.
> 
> The obvious alternative is to have Decodable and Encodable protocols which 
> Codable refines. This would allow us to omit a conformance we don’t need when 
> it can’t be synthesized.
> 
> If conformances are still synthesized individually (i.e. for just Decodable 
> or just Encodable), it would be way too easy to accidentally conform to one 
> or the other and not realize that you’re not conforming to Codable, since the 
> synthesis is invisible. You’d just be missing half of the protocol.
> 
This is the kind of mistake people don’t tend to make often and Swift’s typing 
will alert someone pretty quickly if they make this mistake.  A fixit could 
even be offered if the type is in the same module as it is used incorrectly.  I 
really don’t think it’s that big a deal to expect people to understand the 
differences.  They already need to understand encoders and decoders to make use 
of these protocols and this is just the other side of that distinction.
> If the way out of this is to only synthesize conformance to Codable, then 
> it’s much harder to justify the inclusion of Encodable or Decodable since 
> those would require a manual implementation and would much more rarely be 
> used.
> 
I wouldn’t limit synthesis in that way.

This isn’t that big a deal given that synthesis will do the work for us most of 
the time but I think it’s unfortunate to see these coupled.  There will be 
times when we have to choose between fatalError and maintaining code we don’t 
need.  That’s a bad choice to have to make.  I don’t like designs that impose 
it on me.

> 
> Your reply to Brent mentions using `fatalError` to avoid implementing the 
> direction that isn't needed. I think it would be better if the conformance 
> can reflect what is actually supported by the type. Requiring us to write 
> `fatalError` as a stub for functionality we don’t need is a design problem 
> IMO. I don’t think the extra protocols are really that big a burden. They 
> don’t add any new functionality and are very easy to understand, especially 
> considering the symmetry they would have with the other types you are 
> introducing.
> 
> Coding Keys:
> 
> As others have mentioned, the design of this protocol does not require a 
> value of a conforming type to actually be a valid key (it can return nil for 
> both `intValue` and `stringValue`). This seems problematic to me.
> 
> In the reply to Brent again you mention throwing and `preconditionFailure` as 
> a way to handle incompatible keys. This also seems problematic to me and 
> feels like a design problem. If we really need to support more than one 
> underlying key type and some encoders will reject some key types this 
> information should be captured in the type system. An encoder would only vend 
> a keyed container for keys it actually supports. Ideally the conformance of a 
> type’s CodingKeys could be leveraged to produce a compiler error if an 
> attempt was made to encode this type into an encoder that can’t support its 
> keys. In general, the idea is to produce static errors as close to the origin 
> of the programming mistake as possible.
> 
> I would very much prefer that we don’t defer to runtime assertions or thrown 
> errors, etc for conditions that could be caught statically at compile time 
> given the right design. Other comments have indicated that static guarantees 
> are important to the design (encoders *must* guarantee support of primitives 
> specified by the protocols, etc). Why is a static guarantee of compatible 
> coding keys considered less important?
> 
> I agree that it would be nice to support this in a static way, but while not 
> impossible to represent in the type system, it absolutely explodes the API 
> into a ton of different types and protocols which are not dissimilar. We’ve 
> considered this in the past (see approach #4 in the Alternatives Considered 
> 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-17 Thread David Hart via swift-evolution


> On 17 Mar 2017, at 21:23, Brent Royal-Gordon via swift-evolution 
>  wrote:
> 
>> On Mar 16, 2017, at 12:33 PM, Itai Ferber  wrote:
>> Optional values are accepted and vended directly through the API. The 
>> encode(_:forKey:) methods take optional values directly, and 
>> decodeIfPresent(_:forKey:) vend optional values.
>> 
>> Optional is special in this way — it’s a primitive part of the system. It’s 
>> actually not possible to write an encode(to:) method for Optional, since the 
>> representation of null values is up to the encoder and the format it’s 
>> working in; JSONEncoder, for instance, decides on the representation of nil 
>> (JSON null).
>> 
> Yes—I noticed that later but then forgot to revise the beginning. Sorry about 
> that.
>> It wouldn’t be possible to ask nil to encode itself in a reasonable way.
>> 
> I really think it could be done, at least for most coders. I talked about 
> this in another email, but in summary:
> 
> NSNull would become a primitive type; depending on the format, it would be 
> encoded either as a null value or the absence of a value.
> Optional.some(x) would be encoded the same as x.
> Optional.none would be encoded in the following fashion:
> If the Wrapped associated type was itself an optional type, it would be 
> encoded as a keyed container containing a single entry. That entry's key 
> would be some likely-unique value like "_swiftOptionalDepth"; its value would 
> be the number of levels of optionality before reaching a non-optional type.
> If the Wrapped associated type was non-optional, it would be encoded as an 
> NSNull.
> 
> That sounds complicated, but the runtime already has machinery to coerce 
> Optionals to Objective-C id: Optional.some gets bridged as the Wrapped value, 
> while Optional.none gets bridged as either NSNull or _SwiftNull, which 
> contains a depth. We would simply need to make _SwiftNull conform to Codable, 
> and give it a decoding implementation which was clever enough to realize when 
> it was being asked to decode a different type.
>> What about a more complex enum, like the standard library's 
>> `UnicodeDecodingResult`:
>> 
>> enum UnicodeDecodingResult {
>> case emptyInput
>> case error
>> case scalarValue(UnicodeScalar)
>> }
>> 
>> Or, say, an `Error`-conforming type from one of my projects:
>> 
>> public enum SQLError: Error {
>> case connectionFailed(underlying: Error)
>> case executionFailed(underlying: Error, statement: SQLStatement)
>> case noRecordsFound(statement: SQLStatement)
>> case extraRecordsFound(statement: SQLStatement)
>> case columnInvalid(underlying: Error, key: ColumnSpecifier, statement: 
>> SQLStatement)
>> case valueInvalid(underlying: Error, key: AnySQLColumnKey, statement: 
>> SQLStatement)
>> }
>> 
>> (You can assume that all the types in the associated values are `Codable`.)
>> 
>> Sure — these cases specifically do not derive Codable conformance because 
>> the specific representation to choose is up to you. Two possible ways to 
>> write this, though there are many others (I’m simplifying these cases here a 
>> bit, but you can extrapolate this):
>> 
> Okay, so tl;dr is "There's nothing special to help with this; just encode 
> some indication of the case in one key, and the associated values in separate 
> keys". I suppose that works.
>> Have you given any consideration to supporting types which only need to 
>> decode? That seems likely to be common when interacting with web services.
>> 
>> We have. Ultimately, we decided that the introduction of several protocols 
>> to cover encodability, decodability, and both was too much of a cognitive 
>> overhead, considering the number of other types we’re also introducing. You 
>> can always implement encode(to:) as fatalError().
>> 
> I understand that impulse.
>> Structured types (i.e. types which encode as a collection of properties) 
>> encode and decode their properties in a keyed manner. Keys may be 
>> String-convertible or Int-convertible (or both),
>> 
>> What does "may" mean here? That, at runtime, the encoder will test for the 
>> preferred key type and fall back to the other one? That seems a little bit 
>> problematic.
>> 
>> Yes, this is the case. A lot is left up to the Encoder because it can choose 
>> to do something for its format that your implementation of encode(to:) may 
>> not have considered.
>> If you try to encode something with an Int key in a string-keyed dictionary, 
>> the encoder may choose to stringify the integer if appropriate for the 
>> format. If not, it can reject your key, ignore the call altogether, 
>> preconditionFailure(), etc. It is also perfectly legitimate to write an 
>> Encoder which supports a flat encoding format — in that case, keys are 
>> likely ignored altogether, in which case there is no error to be had. We’d 
>> like to not arbitrarily constrain an implementation unless necessary.
>> 
> Wait, what? If it's ignoring the keys altogether, how does it 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-17 Thread Joe Groff via swift-evolution

> On Mar 17, 2017, at 12:49 PM, Itai Ferber  wrote:
> 
> On 17 Mar 2017, at 12:18, Michael Gottesman wrote:
> 
> 
> On Mar 16, 2017, at 10:23 AM, Joe Groff via swift-evolution 
>  wrote:
> 
> On Mar 16, 2017, at 10:21 AM, Itai Ferber  wrote:
> 
> On 15 Mar 2017, at 19:12, Joe Groff wrote:
> 
> 
> On Mar 15, 2017, at 6:46 PM, Itai Ferber  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 { ... }, 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(_ type: Key.Type) -> Cont 
> where Cont.Key == Key {
> // return something
> }
> 
> This looks promising so far — let's try to make it concrete:
> 
> struct ConcreteContainer : Container {
> typealias Key = K
> }
> 
> func container(_ type: Key.Type) -> Cont 
> where Cont.Key == Key {
> return ConcreteContainer() // error: Cannot convert return expression of 
> type 'ConcreteContainer' 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() 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
> 
> 

You can implement an AnyContainer type that conforms to the Container 
protocol, using an abstract base class that erases the type, and a private 
subclass that forwards the interface to a contained value. 
https://www.bignerdranch.com/blog/breaking-down-type-erasure-in-swift/ 
 runs 
the technique down fairly 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-17 Thread Brent Royal-Gordon via swift-evolution
> On Mar 16, 2017, at 12:33 PM, Itai Ferber  wrote:
> Optional values are accepted and vended directly through the API. The 
> encode(_:forKey:) methods take optional values directly, and 
> decodeIfPresent(_:forKey:) vend optional values.
> 
> Optional is special in this way — it’s a primitive part of the system. It’s 
> actually not possible to write an encode(to:) method for Optional, since the 
> representation of null values is up to the encoder and the format it’s 
> working in; JSONEncoder, for instance, decides on the representation of nil 
> (JSON null).
> 
Yes—I noticed that later but then forgot to revise the beginning. Sorry about 
that.
> It wouldn’t be possible to ask nil to encode itself in a reasonable way.
> 
I really think it could be done, at least for most coders. I talked about this 
in another email, but in summary:

NSNull would become a primitive type; depending on the format, it would be 
encoded either as a null value or the absence of a value.
Optional.some(x) would be encoded the same as x.
Optional.none would be encoded in the following fashion:
If the Wrapped associated type was itself an optional type, it would be encoded 
as a keyed container containing a single entry. That entry's key would be some 
likely-unique value like "_swiftOptionalDepth"; its value would be the number 
of levels of optionality before reaching a non-optional type.
If the Wrapped associated type was non-optional, it would be encoded as an 
NSNull.

That sounds complicated, but the runtime already has machinery to coerce 
Optionals to Objective-C id: Optional.some gets bridged as the Wrapped value, 
while Optional.none gets bridged as either NSNull or _SwiftNull, which contains 
a depth. We would simply need to make _SwiftNull conform to Codable, and give 
it a decoding implementation which was clever enough to realize when it was 
being asked to decode a different type.
> What about a more complex enum, like the standard library's 
> `UnicodeDecodingResult`:
> 
> enum UnicodeDecodingResult {
> case emptyInput
> case error
> case scalarValue(UnicodeScalar)
> }
> 
> Or, say, an `Error`-conforming type from one of my projects:
> 
> public enum SQLError: Error {
> case connectionFailed(underlying: Error)
> case executionFailed(underlying: Error, statement: SQLStatement)
> case noRecordsFound(statement: SQLStatement)
> case extraRecordsFound(statement: SQLStatement)
> case columnInvalid(underlying: Error, key: ColumnSpecifier, statement: 
> SQLStatement)
> case valueInvalid(underlying: Error, key: AnySQLColumnKey, statement: 
> SQLStatement)
> }
> 
> (You can assume that all the types in the associated values are `Codable`.)
> 
> Sure — these cases specifically do not derive Codable conformance because the 
> specific representation to choose is up to you. Two possible ways to write 
> this, though there are many others (I’m simplifying these cases here a bit, 
> but you can extrapolate this):
> 
Okay, so tl;dr is "There's nothing special to help with this; just encode some 
indication of the case in one key, and the associated values in separate keys". 
I suppose that works.
> Have you given any consideration to supporting types which only need to 
> decode? That seems likely to be common when interacting with web services.
> 
> We have. Ultimately, we decided that the introduction of several protocols to 
> cover encodability, decodability, and both was too much of a cognitive 
> overhead, considering the number of other types we’re also introducing. You 
> can always implement encode(to:) as fatalError().
> 
I understand that impulse.
> Structured types (i.e. types which encode as a collection of properties) 
> encode and decode their properties in a keyed manner. Keys may be 
> String-convertible or Int-convertible (or both),
> 
> What does "may" mean here? That, at runtime, the encoder will test for the 
> preferred key type and fall back to the other one? That seems a little bit 
> problematic.
> 
> Yes, this is the case. A lot is left up to the Encoder because it can choose 
> to do something for its format that your implementation of encode(to:) may 
> not have considered.
> If you try to encode something with an Int key in a string-keyed dictionary, 
> the encoder may choose to stringify the integer if appropriate for the 
> format. If not, it can reject your key, ignore the call altogether, 
> preconditionFailure(), etc. It is also perfectly legitimate to write an 
> Encoder which supports a flat encoding format — in that case, keys are likely 
> ignored altogether, in which case there is no error to be had. We’d like to 
> not arbitrarily constrain an implementation unless necessary.
> 
Wait, what? If it's ignoring the keys altogether, how does it know what to 
decode with each call? Do you have to decode in the same order you encoded?

(Or are you saying that the encoder might use the keys to match fields to, say, 
predefined fields in a schema provided to the encoder, but 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-17 Thread Michael Gottesman via swift-evolution

> On Mar 17, 2017, at 12:49 PM, Itai Ferber  wrote:
> 
> On 17 Mar 2017, at 12:18, Michael Gottesman wrote:
> 
> 
> On Mar 16, 2017, at 10:23 AM, Joe Groff via swift-evolution 
>  wrote:
> 
> On Mar 16, 2017, at 10:21 AM, Itai Ferber  wrote:
> 
> On 15 Mar 2017, at 19:12, Joe Groff wrote:
> 
> 
> On Mar 15, 2017, at 6:46 PM, Itai Ferber  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 { ... }, 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(_ type: Key.Type) -> Cont 
> where Cont.Key == Key {
> // return something
> }
> 
> This looks promising so far — let's try to make it concrete:
> 
> struct ConcreteContainer : Container {
> typealias Key = K
> }
> 
> func container(_ type: Key.Type) -> Cont 
> where Cont.Key == Key {
> return ConcreteContainer() // error: Cannot convert return expression of 
> type 'ConcreteContainer' 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() 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
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution 
> 


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-17 Thread Itai Ferber via swift-evolution



On 17 Mar 2017, at 12:18, Michael Gottesman wrote:

On Mar 16, 2017, at 10:23 AM, Joe Groff via swift-evolution 
 wrote:




On Mar 16, 2017, at 10:21 AM, Itai Ferber  wrote:

On 15 Mar 2017, at 19:12, Joe Groff wrote:


On Mar 15, 2017, at 6:46 PM, Itai Ferber  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 { ... }, 
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(_ type: Key.Type) 
-> Cont where Cont.Key == Key {

// return something
}

This looks promising so far — let's try to make it concrete:

struct ConcreteContainer : Container {
typealias Key = K
}

func container(_ type: Key.Type) 
-> Cont where Cont.Key == Key {
return ConcreteContainer() // error: Cannot convert return 
expression of type 'ConcreteContainer' 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() 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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-17 Thread Itai Ferber via swift-evolution

Do you mean versions of the format, or versions of your type?

If the latter, this can be done on a case-by-case basis, as needed. You 
can always do something like


```swift
struct Foo : Codable {
// Name this as appropriate
private let jsonVersion = 1.1
}
```

and have it encode as well.

On 17 Mar 2017, at 11:51, T.J. Usiyan wrote:


Is there any sense of encoding versions (as in, changes to the JSON
representation, for instance?) I don't know that it is necessarily a 
good

idea overall but now is the time to consider it.

On Fri, Mar 17, 2017 at 2:27 PM, Matthew Johnson via swift-evolution <
swift-evolution@swift.org> wrote:



On Mar 17, 2017, at 1:15 PM, Itai Ferber via swift-evolution <
swift-evolution@swift.org> wrote:

On 15 Mar 2017, at 22:58, Zach Waldowski wrote:

Another issue of scale - I had to switch to a native mail client as
replying inline severely broke my webmail client. ;-)

Again, lots of love here. Responses inline.

On Mar 15, 2017, at 6:40 PM, Itai Ferber via swift-evolution <
swift-evolution@swift.org> wrote:
Proposed solution
We will be introducing the following new types:

protocol Codable: Adopted by types to opt into archival. Conformance 
may
be automatically derived in cases where all properties are also 
Codable.


FWIW I think this is acceptable compromise. If the happy path is 
derived
conformances, only-decodable or only-encodable types feel like a lazy 
way

out on the part of a user of the API, and builds a barrier to proper
testing.

[snip]

Structured types (i.e. types which encode as a collection of 
properties)

encode and decode their properties in a keyed manner. Keys may be
String-convertible or Int-convertible (or both), and user types which 
have

properties should declare semantic key enums which map keys to their
properties. Keys must conform to the CodingKey protocol:
public protocol CodingKey { <##snip##> }

A few things here:

The protocol leaves open the possibility of having both a String or 
Int
representation, or neither. What should a coder do in either case? 
Are the
representations intended to be mutually exclusive, or not? The 
protocol
design doesn’t seem particularly matching with the flavor of Swift; 
I’d

expect something along the lines of a CodingKey enum and the protocol
CodingKeyRepresentable. It’s also possible that the concerns of the 
two are

orthogonal enough that they deserve separate container(keyedBy:)
requirements.

The general answer to "what should a coder do" is "what is 
appropriate for
its format". For a format that uses exclusively string keys (like 
JSON),
the string representation (if present on a key) will always be used. 
If the
key has no string representation but does have an integer 
representation,
the encoder may choose to stringify the integer. If the key has 
neither, it

is appropriate for the Encoder to fail in some way.

On the flip side, for totally flat formats, an Encoder may choose to
ignore keys altogether, in which case it doesn’t really matter. The 
choice

is up to the Encoder and its format.

The string and integer representations are not meant to be mutually
exclusive at all, and in fact, where relevant, we encourage providing 
both

types of representations for flexibility.

As for the possibility of having neither representation, this 
question
comes up often. I’d like to summarize the thought process here by 
quoting
some earlier review (apologies for the poor formatting from my mail 
client):


If there are two options, each of which is itself optional, we have 4
possible combinations. But! At the same time we prohibit one 
combination by
what? Runtime error? Why not use a 3-case enum for it? Even further 
down
the rabbit whole there might be a CodingKey<> specialized for a 
concrete
combination, like CodingKey or just 
CodingKey,
but I’m not sure whether our type system will make it useful or 
possible…


public enum CodingKeyValue {
case integer(value: Int)
case string(value: String)
case both(intValue: Int, stringValue: String)
}
public protocol CodingKey {
init?(value: CodingKeyValue)
var value: CodingKeyValue { get }
}

I agree that this certainly feels suboptimal. We’ve certainly 
explored
other possibilities before sticking to this one, so let me try to 
summarize

here:

* Having a concrete 3-case CodingKey enum would preclude the 
possibility
of having neither a stringValue nor an intValue. However, there is a 
lot of

value in having the key types belong to the type being encoded (more
safety, impossible to accidentally mix key types, private keys, 
etc.); if
the CodingKey type itself is an enum (which cannot be inherited 
from), then

this prevents differing key types.
* Your solution as presented is better: CodingKey itself is still a
protocol, and the value itself is the 3-case enum. However, since
CodingKeyValue is not literal-representable, user keys cannot be 
enums
RawRepresentable by CodingKeyValue. That means that the values must 
either
be dynamically returned, or 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-17 Thread Itai Ferber via swift-evolution

On 16 Mar 2017, at 14:29, Matthew Johnson wrote:

This is a fantastic proposal!  I am very much looking forward to 
robust Swift-native encoding and decoding in Foundation.  The compiler 
synthesized conformances is especially great!I want to thank 
everyone who worked on it.  It is clear that a lot of work went into 
the proposal.


The proposal covers a lot of ground so I’m breaking my comments up 
by topic in the order the occur in the proposal.

Thanks for the feedback, Matthew! Responses inline.


Encode / Decode only types:

Brent raised the question of decode only types.  Encode only types are 
also not uncommon when an API accepts an argument payload that gets 
serialized into the body of a request. The compiler synthesis feature 
in the proposal makes providing both encoding and decoding easy in 
common cases but this won’t always work as needed.


The obvious alternative is to have Decodable and Encodable protocols 
which Codable refines.  This would allow us to omit a conformance we 
don’t need when it can’t be synthesized.
If conformances are still synthesized individually (i.e. for just 
`Decodable` or just `Encodable`), it would be way too easy to 
accidentally conform to one or the other and not realize that you’re 
not conforming to `Codable`, since the synthesis is invisible. You’d 
just be missing half of the protocol.


If the way out of this is to only synthesize conformance to `Codable`, 
then it’s much harder to justify the inclusion of `Encodable` or 
`Decodable` since those would require a manual implementation and would 
much more rarely be used.


Your reply to Brent mentions using `fatalError` to avoid implementing 
the direction that isn't needed.  I think it would be better if the 
conformance can reflect what is actually supported by the type.  
Requiring us to write `fatalError` as a stub for functionality we 
don’t need is a design problem IMO.  I don’t think the extra 
protocols are really that big a burden.  They don’t add any new 
functionality and are very easy to understand, especially considering 
the symmetry they would have with the other types you are introducing.


Coding Keys:

As others have mentioned, the design of this protocol does not require 
a value of a conforming type to actually be a valid key (it can return 
nil for both `intValue` and `stringValue`).  This seems problematic to 
me.


In the reply to Brent again you mention throwing and 
`preconditionFailure` as a way to handle incompatible keys.  This also 
seems problematic to me and feels like a design problem. If we really 
need to support more than one underlying key type and some encoders 
will reject some key types this information should be captured in the 
type system.  An encoder would only vend a keyed container for keys it 
actually supports.  Ideally the conformance of a type’s CodingKeys 
could be leveraged to produce a compiler error if an attempt was made 
to encode this type into an encoder that can’t support its keys.  In 
general, the idea is to produce static errors as close to the origin 
of the programming mistake as possible.


I would very much prefer that we don’t defer to runtime assertions 
or thrown errors, etc for conditions that could be caught statically 
at compile time given the right design.  Other comments have indicated 
that static guarantees are important to the design (encoders *must* 
guarantee support of primitives specified by the protocols, etc).  Why 
is a static guarantee of compatible coding keys considered less 
important?
I agree that it would be nice to support this in a static way, but while 
not impossible to represent in the type system, it absolutely explodes 
the API into a ton of different types and protocols which are not 
dissimilar. We’ve considered this in the past (see approach #4 in the 
[Alternatives 
Considered](https://github.com/itaiferber/swift-evolution/blob/637532e2abcbdb9861e424359bb6dac99dc6b638/proposals/-swift-archival-serialization.md#alternatives-considered) 
section) and moved away from it for a reason.


To summarize:

* To statically represent the difference between an encoder which 
supports string keys and one which supports integer keys, we would have 
to introduce two different protocol types (say, `StringKeyEncoder` and 
`IntKeyEncoder`)
* Now that there are two different encoder types, the `Codable` protocol 
also needs to be split up into two — one version which encodes using a 
`StringKeyEncoder` and one version which encodes using an 
`IntKeyEncoder`. If you want to support encoding to an encoder which 
supports both types of keys, we’d need a _third_ Codable protocol 
which takes something that’s `StringKeyEncoder & IntKeyEncoder` 
(because you cannot just conform to both `StringCodable` and 
`IntCodable` — it’s ambiguous when given something that’s 
`StringKeyEncoder & IntKeyEncoder`)
* On encoders which support both string and integer keys, you need 
overloads for `encode(…)`, `encodeIntCodable>(…)`, and 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-17 Thread Joe Groff via swift-evolution

> On Mar 16, 2017, at 12:33 PM, Itai Ferber via swift-evolution 
>  wrote:
> 
> This design struck me as remarkably similar to the reflection system and its 
> `Mirror` type, which is also a separate type describing an original instance. 
> My question was: Did you look at the reflection system when you were building 
> this design? Do you think there might be anything that can be usefully shared 
> between them?
> 
> We did, quite a bit, and spent a lot of time considering reflection and its 
> place in our design. Ultimately, the reflection system does not currently 
> have the features we would need, and although the Swift team has expressed 
> desire to improve the system considerably, it’s not currently a top priority, 
> AFAIK.
> 
> 

Although it isn't sufficient in its current form, I think the key paths 
proposal that recently went out will eventually be able to help a bit here:

https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170313/033998.html
 


If keypaths eventually had the ability to be looked up by name or index, like 
your coding keys are, we could potentially use them as the default coding key 
type instead of synthesizing a new type. That would cut down the number of 
compiler-known things. (I think it's reasonable for coding to do its own thing 
in the meantime, to be clear.)

-Joe___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-17 Thread T.J. Usiyan via swift-evolution
Is there any sense of encoding versions (as in, changes to the JSON
representation, for instance?) I don't know that it is necessarily a good
idea overall but now is the time to consider it.

On Fri, Mar 17, 2017 at 2:27 PM, Matthew Johnson via swift-evolution <
swift-evolution@swift.org> wrote:

>
> On Mar 17, 2017, at 1:15 PM, Itai Ferber via swift-evolution <
> swift-evolution@swift.org> wrote:
>
> On 15 Mar 2017, at 22:58, Zach Waldowski wrote:
>
> Another issue of scale - I had to switch to a native mail client as
> replying inline severely broke my webmail client. ;-)
>
> Again, lots of love here. Responses inline.
>
> On Mar 15, 2017, at 6:40 PM, Itai Ferber via swift-evolution <
> swift-evolution@swift.org> wrote:
> Proposed solution
> We will be introducing the following new types:
>
> protocol Codable: Adopted by types to opt into archival. Conformance may
> be automatically derived in cases where all properties are also Codable.
>
> FWIW I think this is acceptable compromise. If the happy path is derived
> conformances, only-decodable or only-encodable types feel like a lazy way
> out on the part of a user of the API, and builds a barrier to proper
> testing.
>
> [snip]
>
> Structured types (i.e. types which encode as a collection of properties)
> encode and decode their properties in a keyed manner. Keys may be
> String-convertible or Int-convertible (or both), and user types which have
> properties should declare semantic key enums which map keys to their
> properties. Keys must conform to the CodingKey protocol:
> public protocol CodingKey { <##snip##> }
>
> A few things here:
>
> The protocol leaves open the possibility of having both a String or Int
> representation, or neither. What should a coder do in either case? Are the
> representations intended to be mutually exclusive, or not? The protocol
> design doesn’t seem particularly matching with the flavor of Swift; I’d
> expect something along the lines of a CodingKey enum and the protocol
> CodingKeyRepresentable. It’s also possible that the concerns of the two are
> orthogonal enough that they deserve separate container(keyedBy:)
> requirements.
>
> The general answer to "what should a coder do" is "what is appropriate for
> its format". For a format that uses exclusively string keys (like JSON),
> the string representation (if present on a key) will always be used. If the
> key has no string representation but does have an integer representation,
> the encoder may choose to stringify the integer. If the key has neither, it
> is appropriate for the Encoder to fail in some way.
>
> On the flip side, for totally flat formats, an Encoder may choose to
> ignore keys altogether, in which case it doesn’t really matter. The choice
> is up to the Encoder and its format.
>
> The string and integer representations are not meant to be mutually
> exclusive at all, and in fact, where relevant, we encourage providing both
> types of representations for flexibility.
>
> As for the possibility of having neither representation, this question
> comes up often. I’d like to summarize the thought process here by quoting
> some earlier review (apologies for the poor formatting from my mail client):
>
> If there are two options, each of which is itself optional, we have 4
> possible combinations. But! At the same time we prohibit one combination by
> what? Runtime error? Why not use a 3-case enum for it? Even further down
> the rabbit whole there might be a CodingKey<> specialized for a concrete
> combination, like CodingKey or just CodingKey,
> but I’m not sure whether our type system will make it useful or possible…
>
> public enum CodingKeyValue {
> case integer(value: Int)
> case string(value: String)
> case both(intValue: Int, stringValue: String)
> }
> public protocol CodingKey {
> init?(value: CodingKeyValue)
> var value: CodingKeyValue { get }
> }
>
> I agree that this certainly feels suboptimal. We’ve certainly explored
> other possibilities before sticking to this one, so let me try to summarize
> here:
>
> * Having a concrete 3-case CodingKey enum would preclude the possibility
> of having neither a stringValue nor an intValue. However, there is a lot of
> value in having the key types belong to the type being encoded (more
> safety, impossible to accidentally mix key types, private keys, etc.); if
> the CodingKey type itself is an enum (which cannot be inherited from), then
> this prevents differing key types.
> * Your solution as presented is better: CodingKey itself is still a
> protocol, and the value itself is the 3-case enum. However, since
> CodingKeyValue is not literal-representable, user keys cannot be enums
> RawRepresentable by CodingKeyValue. That means that the values must either
> be dynamically returned, or (for attaining the benefits that we want to
> give users — easy representation, autocompletion, etc.) the type has to be
> a struct with static lets on it giving the CodingKeyValues. This certainly
> works, but is likely not what 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-17 Thread Matthew Johnson via swift-evolution

> On Mar 17, 2017, at 1:15 PM, Itai Ferber via swift-evolution 
>  wrote:
> 
> On 15 Mar 2017, at 22:58, Zach Waldowski wrote:
> 
> 
> Another issue of scale - I had to switch to a native mail client as replying 
> inline severely broke my webmail client. ;-)
> 
> Again, lots of love here. Responses inline.
> On Mar 15, 2017, at 6:40 PM, Itai Ferber via swift-evolution 
>  wrote:
> Proposed solution
> We will be introducing the following new types:
> 
> protocol Codable: Adopted by types to opt into archival. Conformance may be 
> automatically derived in cases where all properties are also Codable.
> 
> FWIW I think this is acceptable compromise. If the happy path is derived 
> conformances, only-decodable or only-encodable types feel like a lazy way out 
> on the part of a user of the API, and builds a barrier to proper testing.
> 
> [snip]
> 
> Structured types (i.e. types which encode as a collection of properties) 
> encode and decode their properties in a keyed manner. Keys may be 
> String-convertible or Int-convertible (or both), and user types which have 
> properties should declare semantic key enums which map keys to their 
> properties. Keys must conform to the CodingKey protocol:
> public protocol CodingKey { <##snip##> }
> 
> A few things here:
> 
> The protocol leaves open the possibility of having both a String or Int 
> representation, or neither. What should a coder do in either case? Are the 
> representations intended to be mutually exclusive, or not? The protocol 
> design doesn’t seem particularly matching with the flavor of Swift; I’d 
> expect something along the lines of a CodingKey enum and the protocol 
> CodingKeyRepresentable. It’s also possible that the concerns of the two are 
> orthogonal enough that they deserve separate container(keyedBy:) requirements.
> 
> The general answer to "what should a coder do" is "what is appropriate for 
> its format". For a format that uses exclusively string keys (like JSON), the 
> string representation (if present on a key) will always be used. If the key 
> has no string representation but does have an integer representation, the 
> encoder may choose to stringify the integer. If the key has neither, it is 
> appropriate for the Encoder to fail in some way.
> 
> On the flip side, for totally flat formats, an Encoder may choose to ignore 
> keys altogether, in which case it doesn’t really matter. The choice is up to 
> the Encoder and its format.
> 
> The string and integer representations are not meant to be mutually exclusive 
> at all, and in fact, where relevant, we encourage providing both types of 
> representations for flexibility.
> 
> As for the possibility of having neither representation, this question comes 
> up often. I’d like to summarize the thought process here by quoting some 
> earlier review (apologies for the poor formatting from my mail client):
> 
> 
> If there are two options, each of which is itself optional, we have 4 
> possible combinations. But! At the same time we prohibit one combination by 
> what? Runtime error? Why not use a 3-case enum for it? Even further down the 
> rabbit whole there might be a CodingKey<> specialized for a concrete 
> combination, like CodingKey or just CodingKey, 
> but I’m not sure whether our type system will make it useful or possible…
> 
> public enum CodingKeyValue {
> case integer(value: Int)
> case string(value: String)
> case both(intValue: Int, stringValue: String)
> }
> public protocol CodingKey {
> init?(value: CodingKeyValue)
> var value: CodingKeyValue { get }
> }
> 
> I agree that this certainly feels suboptimal. We’ve certainly explored other 
> possibilities before sticking to this one, so let me try to summarize here:
> 
> * Having a concrete 3-case CodingKey enum would preclude the possibility of 
> having neither a stringValue nor an intValue. However, there is a lot of 
> value in having the key types belong to the type being encoded (more safety, 
> impossible to accidentally mix key types, private keys, etc.); if the 
> CodingKey type itself is an enum (which cannot be inherited from), then this 
> prevents differing key types.
> * Your solution as presented is better: CodingKey itself is still a protocol, 
> and the value itself is the 3-case enum. However, since CodingKeyValue is not 
> literal-representable, user keys cannot be enums RawRepresentable by 
> CodingKeyValue. That means that the values must either be dynamically 
> returned, or (for attaining the benefits that we want to give users — easy 
> representation, autocompletion, etc.) the type has to be a struct with static 
> lets on it giving the CodingKeyValues. This certainly works, but is likely 
> not what a developer would have in mind when working with the API; the power 
> of enums in Swift makes them very easy to reach for, and I’m thinking most 
> users would expect their keys to be enums. We’d like to leverage that where 
> we can, 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-17 Thread Itai Ferber via swift-evolution



On 15 Mar 2017, at 22:58, Zach Waldowski wrote:

Another issue of scale - I had to switch to a native mail client as 
replying inline severely broke my webmail client. ;-)


Again, lots of love here. Responses inline.

On Mar 15, 2017, at 6:40 PM, Itai Ferber via swift-evolution 
 wrote:

Proposed solution
We will be introducing the following new types:

protocol Codable: Adopted by types to opt into archival. Conformance 
may be automatically derived in cases where all properties are also 
Codable.
FWIW I think this is acceptable compromise. If the happy path is 
derived conformances, only-decodable or only-encodable types feel like 
a lazy way out on the part of a user of the API, and builds a barrier 
to proper testing.

[snip]

Structured types (i.e. types which encode as a collection of 
properties) encode and decode their properties in a keyed manner. 
Keys may be String-convertible or Int-convertible (or both), and user 
types which have properties should declare semantic key enums which 
map keys to their properties. Keys must conform to the CodingKey 
protocol:

public protocol CodingKey { <##snip##> }


A few things here:

The protocol leaves open the possibility of having both a String or 
Int representation, or neither. What should a coder do in either case? 
Are the representations intended to be mutually exclusive, or not? The 
protocol design doesn’t seem particularly matching with the flavor 
of Swift; I’d expect something along the lines of a CodingKey enum 
and the protocol CodingKeyRepresentable. It’s also possible that the 
concerns of the two are orthogonal enough that they deserve separate 
container(keyedBy:) requirements.
The general answer to "what should a coder do" is "what is appropriate 
for its format". For a format that uses exclusively string keys (like 
JSON), the string representation (if present on a key) will always be 
used. If the key has no string representation but does have an integer 
representation, the encoder may choose to stringify the integer. If the 
key has neither, it is appropriate for the `Encoder` to fail in some 
way.


On the flip side, for totally flat formats, an `Encoder` may choose to 
ignore keys altogether, in which case it doesn’t really matter. The 
choice is up to the `Encoder` and its format.


The string and integer representations are not meant to be mutually 
exclusive at all, and in fact, where relevant, we encourage providing 
both types of representations for flexibility.


As for the possibility of having neither representation, this question 
comes up often. I’d like to summarize the thought process here by 
quoting some earlier review (apologies for the poor formatting from my 
mail client):


If there are two options, each of which is itself optional, we have 4 
possible combinations. But! At the same time we prohibit one 
combination by what? Runtime error? Why not use a 3-case enum for it? 
Even further down the rabbit whole there might be a CodingKey<> 
specialized for a concrete combination, like 
CodingKey or just CodingKey, but I’m 
not sure whether our type system will make it useful or possible…


public enum CodingKeyValue {
  case integer(value: Int)
  case string(value: String)
  case both(intValue: Int, stringValue: String)
}
public protocol CodingKey {
  init?(value: CodingKeyValue)
  var value: CodingKeyValue { get }
}
I agree that this certainly feels suboptimal. We’ve certainly 
explored other possibilities before sticking to this one, so let me 
try to summarize here:


* Having a concrete 3-case CodingKey enum would preclude the 
possibility of having neither a stringValue nor an intValue. However, 
there is a lot of value in having the key types belong to the type 
being encoded (more safety, impossible to accidentally mix key types, 
private keys, etc.); if the CodingKey type itself is an enum (which 
cannot be inherited from), then this prevents differing key types.
* Your solution as presented is better: CodingKey itself is still a 
protocol, and the value itself is the 3-case enum. However, since 
CodingKeyValue is not literal-representable, user keys cannot be enums 
RawRepresentable by CodingKeyValue. That means that the values must 
either be dynamically returned, or (for attaining the benefits that we 
want to give users — easy representation, autocompletion, etc.) the 
type has to be a struct with static lets on it giving the 
CodingKeyValues. This certainly works, but is likely not what a 
developer would have in mind when working with the API; the power of 
enums in Swift makes them very easy to reach for, and I’m thinking 
most users would expect their keys to be enums. We’d like to 
leverage that where we can, especially since RawRepresentable enums 
are appropriate in the vast majority of use cases.
* Three separate CodingKey protocols (one for Strings, one for Ints, 
and one for both). You could argue that this is the most correct 
version, since it most clearly 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-17 Thread Tony Parker via swift-evolution
Hi Matt,

> On Mar 17, 2017, at 6:39 AM, Matt Diephouse via swift-evolution 
>  wrote:
> 
> I have two related questions:
> 
>   1. Why was Swift 4 chosen as the target release for adding archival and 
> serialization?
> 
>   2. Given Swift compatibility requirements going forward, how much will the 
> design of these APIs be able to change?

I responded to this partially elsewhere in this thread, but the summary is: 
Swift developers are working with archiving and serialization right now and 
they deserve a better API that they can use as soon as possible. The language 
will always continue to evolve and improve.

> 
> The overall impression I get from the APIs is that they’ve been shaped by the 
> current limitations of Swift (a familiar constraint). There are a number of 
> likely future improvements that would likely significantly benefit this 
> proposal:
> 
>   1. Throwing subscripts, as mentioned here
> 
>   2. Improved generics, such that protocols could be used instead of abstract 
> base classes
> 
>   3. Improved type inference, as mentioned previously in the thread about 
> inferring return types
> 
>   4. Dynamism/reflection in whatever form Swift adds would be very closely 
> related, but more general, potentially influencing this design
> 
> Some of these could lead to improved, non-additive APIs. Will the archival 
> and serialization APIs be able to be updated in response to improvements like 
> these?

Yes, that is the plan. Our job during every release is to take a look at our 
APIs and implementations and make them better. Often times that means adjusting 
to new language features and other library features as they are released.

Another thing to remember is that library features can help drive language 
features. By releasing API like this, we are providing great motivation to pick 
what language features are most important going forward.

- Tony

> 
>> On Mar 16, 2017, at 5:12 PM, Itai Ferber via swift-evolution 
>> > wrote:
>> 
>> If throwing subscripts made it in the Swift 4 timeframe, then we would 
>> certainly consider it.
>> 
>> On 16 Mar 2017, at 13:19, Matthew Johnson wrote:
>> 
>> 
>>> On Mar 16, 2017, at 3:01 PM, Itai Ferber >> > wrote:
>>> 
>>> Subscripts, by the way, would not help here, since they cannot throw. 
>>> decode must be able to throw.
>>> SR-238 
>>> ;
>>>  for Apple folks, 28775436.
>>> 
>> They don’t “help” but they do provide a more natural interface.  If the 
>> Foundation team feels a more wordy interface is necessary that is ok.
>> 
>> I specifically mentioned that they can’t throw yet.  Throwing subscripts 
>> would make a good companion proposal if they could fit into the Swift 4 
>> timeframe.  If not, then yes we need a method rather than a subscript.  But 
>> if we can get throwing subscripts into Swift 4, why not use Swift’s first 
>> class syntactic support for keyed access to keyed containers?
>> 
>>> On 16 Mar 2017, at 11:46, Matthew Johnson via swift-evolution wrote:
>>> 
>>> 
>>> 
 On Mar 16, 2017, at 1:34 PM, Zach Waldowski via swift-evolution 
 > wrote:
 
 On Thu, Mar 16, 2017, at 02:23 PM, Matthew Johnson via swift-evolution 
 wrote:
> I don’t have an example but I don’t see a problem either.  There are two 
> options for specifying the return type manually.  We can use the 
> signature you used above and use `as` to specify the expected type:
> 
> let i = decode(.myKey) as Int
 
 The awkwardness of this syntax is exactly what I'm referring to. Would a 
 beginner know to use "as Int" or ": Int"? Why would they? The "prettiness" 
 of the simple case doesn't make up for how difficult it is to understand 
 and fix its failure cases.
 
 Any official Swift or Foundation API shouldn't, or shouldn't need to, make 
 use of "tricky" syntax.
>>> 
>>> I don’t think this is especially tricky.  Nevertheless, we can avoid 
>>> requiring this syntax by moving the type argument to the end and providing 
>>> a default.  But I think return type inference is worth supporting.  It has 
>>> become widely adopted by the community already in this use case.
>>> 
 
> If we don’t support this in Foundation we will continue to see 3rd party 
> libraries that do this.
 
 The proposal's been out for less than 24 hours, is it really productive to 
 already be taking our ball and go home over such a minor thing?
>>> 
>>> I don’t think that’s what I’m doing at all.  This is a fantastic proposal.  
>>> I’m still working through it and writing up my more detailed thoughts.
>>> 
>>> That said, as with many (most?) first drafts, there is room for 
>>> improvement.  I think it’s worth pointing out the syntax that 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-17 Thread Tony Parker via swift-evolution
Hi Karl,

> On Mar 17, 2017, at 12:20 AM, Karl Wagner via swift-evolution 
>  wrote:
> 
> 
>> On 16 Mar 2017, at 21:48, Slava Pestov via swift-evolution 
>> > wrote:
>> 
>> Hi Itai,
>> 
>> I’m wondering what the motivation is for keeping this as part of Foundation 
>> and not the standard library. It seems like you’re landing an implementation 
>> of this in the Foundation overlay on master, and another copy of all the 
>> code will have to go into swift-corelibs-foundation. This seems suboptimal. 
>> Or are there future plans to unify the Foundation overlay with 
>> corelibs-foundation somehow?
>> 
>> Also the implementation uses some Foundation-isms (NSMutableArray, NSNumber) 
>> and it would be nice to stick with idiomatic Swift as much as possible 
>> instead.
>> 
>> Finally you should take a look at the integer protocol work 
>> (https://github.com/apple/swift-evolution/blob/master/proposals/0104-improved-integers.md
>>  
>> )
>>  to replace the repetitive code surrounding primitive types, however I don’t 
>> know if this has landed in master yet.
>> 
>> Slava
> 
> I agree that the protocols should be part of the standard library rather than 
> Foundation. As far as I can make out, the only part of this proposal that 
> actually requires Foundation is the use of the “Data” type (which itself is a 
> strange and often frustrating omission from the standard library). The actual 
> concrete encoders can live in Foundation.
> 
> Generally my opinion is that the proposed feature is nice. Everybody hates 
> NSCoder and having to write those required initialisers on your UIViews and 
> whatnot. At its core, it’s not really very different from any other Swift 
> archiving library which exists today, except that it’s backed with layer upon 
> layer of compiler-generated magic to make it less verbose. The things I don’t 
> like:
> 
> 1) While making things less verbose is commendable, automatically generating 
> the encoding functions could be an anti-feature. “Codable” is for properties 
> with persistable values only, which is a level of semantics which goes above 
> the type-system. We don’t generate Equatable conformance for structs whose 
> elements are all Equatable; it’s a big leap to go from “this data type is 
> persistable” to “the value of this variable should be persisted” - for one 
> thing, the value may not have meaning to others (e.g. a file-handle as an 
> Int32) or it may contain sensitive user-data in a String. The encoding 
> function isn’t just boilerplate - you *should* think about it; otherwise who 
> knows what kind of data you’re leaking?
> 
> => One possible solution would be to have “Codable" as a regular protocol, 
> and refine it with “AutoCodable" which contains the magic. Just so there is a 
> little extra step where you think “do I want this to be generated?”.

The number one complaint we have about NSCoding (and this complaint predates 
Swift by a long shot) is that too much boilerplate is required for really 
simple data structures. Resolving this issue is one of our primary goals for 
this API.

There are a lot of benefits to keeping one protocol in place instead of making 
another one for “auto” codable: API which accepts Codable things does not need 
to have two entry points; there is one concept of Codable instead of two; you 
can “buy in” to more complex behavior by implementing parts of Codable (e.g., 
just the keys if you simply want to change the names of the JSON keys).

> 
> 2) More generally, though, I don’t support the idea of the Foundation module 
> introducing extensions to the Swift language that no other developer of any 
> other module has the chance to do, with an aside that some reflection API 
> which doesn’t exist yet might possibly make it less magic in the future. My 
> jaw hit the floor when I saw this was part of the proposal, and that it 
> wasn’t for the standard library. Could you imagine, if somebody proposed 
> their own magic protocols for AlamoFire or Kitura or any other Swift library? 
> It would be a non-starter. It *should* be a non-starter.
> 
> => Do we have a policy about module-specific compiler magic such as this?
> => Can we move any of the magic (e.g. CodableKeys generation) to the standard 
> library?
> 
> I develop a lot for platforms, or for scenarios, where Foundation is not 
> supported nor desirable. Considering that people are taught to prefer library 
> code to rolling their own, and that humans are generally quite receptive to 
> shortcuts at the expense of correctness, if this machinery exists at all we 
> can expect it to spread. It would totally kill libraries such as SwiftJSON or 
> whatever else you currently use. The fact that such a fundamental and 
> widespread feature would now live in a monolithic module I can’t access would 
> significantly 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-17 Thread Matt Diephouse via swift-evolution
I have two related questions:

  1. Why was Swift 4 chosen as the target release for adding archival and 
serialization?

  2. Given Swift compatibility requirements going forward, how much will the 
design of these APIs be able to change?

The overall impression I get from the APIs is that they’ve been shaped by the 
current limitations of Swift (a familiar constraint). There are a number of 
likely future improvements that would likely significantly benefit this 
proposal:

  1. Throwing subscripts, as mentioned here

  2. Improved generics, such that protocols could be used instead of abstract 
base classes

  3. Improved type inference, as mentioned previously in the thread about 
inferring return types

  4. Dynamism/reflection in whatever form Swift adds would be very closely 
related, but more general, potentially influencing this design

Some of these could lead to improved, non-additive APIs. Will the archival and 
serialization APIs be able to be updated in response to improvements like these?

> On Mar 16, 2017, at 5:12 PM, Itai Ferber via swift-evolution 
>  wrote:
> 
> If throwing subscripts made it in the Swift 4 timeframe, then we would 
> certainly consider it.
> 
> On 16 Mar 2017, at 13:19, Matthew Johnson wrote:
> 
> 
>> On Mar 16, 2017, at 3:01 PM, Itai Ferber > > wrote:
>> 
>> Subscripts, by the way, would not help here, since they cannot throw. decode 
>> must be able to throw.
>> SR-238 
>> ;
>>  for Apple folks, 28775436.
>> 
> They don’t “help” but they do provide a more natural interface.  If the 
> Foundation team feels a more wordy interface is necessary that is ok.
> 
> I specifically mentioned that they can’t throw yet.  Throwing subscripts 
> would make a good companion proposal if they could fit into the Swift 4 
> timeframe.  If not, then yes we need a method rather than a subscript.  But 
> if we can get throwing subscripts into Swift 4, why not use Swift’s first 
> class syntactic support for keyed access to keyed containers?
> 
>> On 16 Mar 2017, at 11:46, Matthew Johnson via swift-evolution wrote:
>> 
>> 
>> 
>>> On Mar 16, 2017, at 1:34 PM, Zach Waldowski via swift-evolution 
>>> > wrote:
>>> 
>>> On Thu, Mar 16, 2017, at 02:23 PM, Matthew Johnson via swift-evolution 
>>> wrote:
 I don’t have an example but I don’t see a problem either.  There are two 
 options for specifying the return type manually.  We can use the signature 
 you used above and use `as` to specify the expected type:
 
 let i = decode(.myKey) as Int
>>> 
>>> The awkwardness of this syntax is exactly what I'm referring to. Would a 
>>> beginner know to use "as Int" or ": Int"? Why would they? The "prettiness" 
>>> of the simple case doesn't make up for how difficult it is to understand 
>>> and fix its failure cases.
>>> 
>>> Any official Swift or Foundation API shouldn't, or shouldn't need to, make 
>>> use of "tricky" syntax.
>> 
>> I don’t think this is especially tricky.  Nevertheless, we can avoid 
>> requiring this syntax by moving the type argument to the end and providing a 
>> default.  But I think return type inference is worth supporting.  It has 
>> become widely adopted by the community already in this use case.
>> 
>>> 
 If we don’t support this in Foundation we will continue to see 3rd party 
 libraries that do this.
>>> 
>>> The proposal's been out for less than 24 hours, is it really productive to 
>>> already be taking our ball and go home over such a minor thing?
>> 
>> I don’t think that’s what I’m doing at all.  This is a fantastic proposal.  
>> I’m still working through it and writing up my more detailed thoughts.
>> 
>> That said, as with many (most?) first drafts, there is room for improvement. 
>>  I think it’s worth pointing out the syntax that many of us would like to 
>> use for decoding and at least considering including it in the proposal.  If 
>> the answer is that it’s trivial for those who want to use subscripts to 
>> write the wrappers for return type inference and / or subscripts themselves 
>> that’s ok.  But it’s a fair topic for discussion and should at least be 
>> addressed as an alternative that was rejected for a specific reason.
>> 
>>> 
>>> Zach Waldowski
>>> z...@waldowski.me 
>>> 
>>> 
>>> 
>>> 
>>> ___
>>> swift-evolution mailing list
>>> swift-evolution@swift.org 
>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>> 
>> 
>> ___
>> swift-evolution mailing list
>> swift-evolution@swift.org 
>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>> 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-17 Thread David Hart via swift-evolution


> On 16 Mar 2017, at 22:36, Itai Ferber  wrote:
> 
> On 16 Mar 2017, at 13:27, David Hart wrote:
> 
> > On 16 Mar 2017, at 20:55, Itai Ferber via swift-evolution 
> >  wrote:
> 
> I’m going to reply to this thread as a whole — apologies if there’s someone’s 
> comment that I’ve missed.
> 
> This is something that has come up in internal review, and we’ve certainly 
> given it thought. As Zach has already mentioned, the primary concern with 
> overloading based on return type is ambiguity.
> There are many cases in which Swift’s type system currently does not handle 
> ambiguity in the way that you would expect, and it can be very surprising. 
> For instance,
> 
> func foo() -> Int { return 42 }
> func foo() -> Double { return .pi }
> func consumesInt(_ x : Int) { print(x) }
> 
> let x = foo() // Ambiguous use of foo()
> consumesInt(x) // Even though x is going to be used as an Int
> let y: Int = x // Same here
> let x = foo() as Int works now, but it actually didn’t always — until a 
> somewhat recent version of Swift AFAICT, the only way to resolve the 
> ambiguity was through let x: Int = foo(). This has since been fixed, but it 
> was very confusing to try to figure out the unambiguous way to call it.
> 
> Keep in mind that this isn’t an unreasonable thing to want to do:
> 
> struct Foo {
> var x: Int
> init(from decoder: Decoder) throws {
> let container = try decoder.container(keyedBy: CodingKeys.self)
> 
> // Want to process an element before it’s assigned.
> let x = container.decode(forKey: .x) // Ambiguous call
> 
> // Or whatever.
> if x < 0 {
> self.x = x + 100
> else {
> self.x = x * 200
> }
> }
> }
> You can write let x: Int = container.decode(…) or let x = container.decode(…) 
> as Int, but this isn’t always intuitive.
> That’s where I disagree. Let me try to prove my point:
> 
> You bring up the example of having to store the decoded value in a variable 
> before setting it to a typed property. But its also not unreasonable to want 
> to do the same thing when encoding the value, possibly storing it into a 
> different type. If we follow that argument, its also not very intuitive to 
> have to do
> 
> container.encode(x as Double, forKey: .x).
> 
> Wouldn’t that be an argument to have an API like this:
> 
> func encode(_ value: Data?, forKey key: Key, as type: T.Type) throws
> 
> I don’t agree that these are equivalent cases.
> 
> Here, for an as cast to be valid, the type of x must be an existential (I’m 
> guessing Any).
> The original container.encode(x, forKey: .x) call is not ambiguous because x 
> has no type, but rather because the type of x does not match any of the 
> overloads. You would get the same error as if you wrote
> 
> struct NonCodableFoo {}
> let x = NonCodableFoo()
> container.encode(x, forKey: .x)
> You have to convert the type to something that fits one of the overloads.
> 
Yes, sorry, I wasn't thinking straight.
> On encode, there cannot be any true ambiguity because it’s not possible to 
> satisfy more than one of these concrete overloads. You cannot have a thing 
> with a type which would satisfy both, say, Int and Double.
> 
> I would argue that type inference is a core feature in Swift and that we 
> should embrace it. I believe that in most cases the return value of encode 
> will be stored into a typed property and type inference will do the right 
> thing. In the few cases where the type has to be enforced, the patterns you 
> mention above are not weird syntax; they are used and useful all over Swift:
> 
> Sure, but I think these cases are not equivalent.
> 
> let cgFloat: CGFloat = 42
> 
> 42 has a default value of Int, but since CGFloat is ExpressibleByIntLiteral, 
> this becomes the equivalent of writing let cfFloat = CGFloat(42), which would 
> not be ambiguous without the CGFloat(); you would just get an Int.
> 
> With let x = container.decode(forKey: .x), has has no type unless otherwise 
> specified.
> 
> let pi = 3.14159265359 as Float
> 
> Same here, but with Double instead of Int, and Float instead of CGFloat…
> 
> let person = factory.get() // potential feature in Generics Manifesto
> 
> This isn’t type inference. This is type specification, which is exactly what 
> we are trying to do. At the moment, explicit type specification has a 
> different syntax: passing a metatype as an argument.
> 
> If this feature were available, this is what we would use.
> 
> The way I think about it is that the type argument is already there as a 
> generic parameter. Adding an extra argument that needs to be explicitly given 
> on every single call feels like unneeded verbosity to me.
> 
> For consideration: why does let person = factory.get() seem 
> reasonable, but let person = factory.get(Person.self) does not?
> 
I'm sorry, I was just very bad at expressing myself.  Let me try again:

I'm not against type specialization: I think I'm just against the meta type 
argument variant (which is all we currently have 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-17 Thread Karl Wagner via swift-evolution

> On 16 Mar 2017, at 21:48, Slava Pestov via swift-evolution 
>  wrote:
> 
> Hi Itai,
> 
> I’m wondering what the motivation is for keeping this as part of Foundation 
> and not the standard library. It seems like you’re landing an implementation 
> of this in the Foundation overlay on master, and another copy of all the code 
> will have to go into swift-corelibs-foundation. This seems suboptimal. Or are 
> there future plans to unify the Foundation overlay with corelibs-foundation 
> somehow?
> 
> Also the implementation uses some Foundation-isms (NSMutableArray, NSNumber) 
> and it would be nice to stick with idiomatic Swift as much as possible 
> instead.
> 
> Finally you should take a look at the integer protocol work 
> (https://github.com/apple/swift-evolution/blob/master/proposals/0104-improved-integers.md
>  
> )
>  to replace the repetitive code surrounding primitive types, however I don’t 
> know if this has landed in master yet.
> 
> Slava

I agree that the protocols should be part of the standard library rather than 
Foundation. As far as I can make out, the only part of this proposal that 
actually requires Foundation is the use of the “Data” type (which itself is a 
strange and often frustrating omission from the standard library). The actual 
concrete encoders can live in Foundation.

Generally my opinion is that the proposed feature is nice. Everybody hates 
NSCoder and having to write those required initialisers on your UIViews and 
whatnot. At its core, it’s not really very different from any other Swift 
archiving library which exists today, except that it’s backed with layer upon 
layer of compiler-generated magic to make it less verbose. The things I don’t 
like:

1) While making things less verbose is commendable, automatically generating 
the encoding functions could be an anti-feature. “Codable” is for properties 
with persistable values only, which is a level of semantics which goes above 
the type-system. We don’t generate Equatable conformance for structs whose 
elements are all Equatable; it’s a big leap to go from “this data type is 
persistable” to “the value of this variable should be persisted” - for one 
thing, the value may not have meaning to others (e.g. a file-handle as an 
Int32) or it may contain sensitive user-data in a String. The encoding function 
isn’t just boilerplate - you *should* think about it; otherwise who knows what 
kind of data you’re leaking?

=> One possible solution would be to have “Codable" as a regular protocol, and 
refine it with “AutoCodable" which contains the magic. Just so there is a 
little extra step where you think “do I want this to be generated?”.

2) More generally, though, I don’t support the idea of the Foundation module 
introducing extensions to the Swift language that no other developer of any 
other module has the chance to do, with an aside that some reflection API which 
doesn’t exist yet might possibly make it less magic in the future. My jaw hit 
the floor when I saw this was part of the proposal, and that it wasn’t for the 
standard library. Could you imagine, if somebody proposed their own magic 
protocols for AlamoFire or Kitura or any other Swift library? It would be a 
non-starter. It *should* be a non-starter.

=> Do we have a policy about module-specific compiler magic such as this?
=> Can we move any of the magic (e.g. CodableKeys generation) to the standard 
library?

I develop a lot for platforms, or for scenarios, where Foundation is not 
supported nor desirable. Considering that people are taught to prefer library 
code to rolling their own, and that humans are generally quite receptive to 
shortcuts at the expense of correctness, if this machinery exists at all we can 
expect it to spread. It would totally kill libraries such as SwiftJSON or 
whatever else you currently use. The fact that such a fundamental and 
widespread feature would now live in a monolithic module I can’t access would 
significantly spoil the language for me.

- Karl___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Slava Pestov via swift-evolution

> On Mar 16, 2017, at 4:00 PM, Matthew Johnson via swift-evolution 
>  wrote:
> 
> 
> 
> Sent from my iPad
> 
>> On Mar 16, 2017, at 5:54 PM, Ben Rimmington  wrote:
>> 
>> 
 On 16 Mar 2017, at 21:14, Matthew Johnson wrote:
 
 On Mar 16, 2017, at 4:12 PM, Itai Ferber  wrote:
 
 If throwing subscripts made it in the Swift 4 timeframe, then we would 
 certainly consider it.
>>> 
>>> Cool.  Any comment from the core team on whether this is a possibility?  If 
>>> it is and nobody else wants to write a proposal I would be willing to do it.
>> 
>> "Throwing Properties and Subscripts" proposal by Brent Royal-Gordon (12 
>> months ago):
>> 
>> 
> 
> Oh, great!  I had forgotten about this.  It would be awesome if we could 
> revive this for Swift 4 especially so it can be considered as part of the 
> interface of this API.  Even if Foundation doesn't adopt the, they would be a 
> great complement for those of us who would prefer the lighter syntax and are 
> willing to use our own wrapper.

I think the limiting factor here is not reviewing the proposal, but 
implementing it. If someone comes up with a prototype implementation it would 
increase the odds of the proposal being accepted.

A big part of this would just be untangling a pile of code in SILGen for 
emitting function call arguments and applying them. Right now there’s too much 
duplication between method calls and property access and subscripts. I need to 
do some work in this area to implement default arguments for subscripts; I 
think this can be accomplished through some refactoring and deleting of code. I 
haven’t thought about throwing properties and subscripts but I imagine it would 
be similar.

Slava

> 
>> 
>> -- Ben
>> 
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org 
> https://lists.swift.org/mailman/listinfo/swift-evolution 
> 
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Mar 16, 2017, at 5:54 PM, Ben Rimmington  wrote:
> 
> 
>>> On 16 Mar 2017, at 21:14, Matthew Johnson wrote:
>>> 
>>> On Mar 16, 2017, at 4:12 PM, Itai Ferber  wrote:
>>> 
>>> If throwing subscripts made it in the Swift 4 timeframe, then we would 
>>> certainly consider it.
>> 
>> Cool.  Any comment from the core team on whether this is a possibility?  If 
>> it is and nobody else wants to write a proposal I would be willing to do it.
> 
> "Throwing Properties and Subscripts" proposal by Brent Royal-Gordon (12 
> months ago):
> 
> 

Oh, great!  I had forgotten about this.  It would be awesome if we could revive 
this for Swift 4 especially so it can be considered as part of the interface of 
this API.  Even if Foundation doesn't adopt the, they would be a great 
complement for those of us who would prefer the lighter syntax and are willing 
to use our own wrapper.

> 
> -- Ben
> 

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Ben Rimmington via swift-evolution

> On 16 Mar 2017, at 21:14, Matthew Johnson wrote:
> 
>> On Mar 16, 2017, at 4:12 PM, Itai Ferber  wrote:
>> 
>> If throwing subscripts made it in the Swift 4 timeframe, then we would 
>> certainly consider it.
> 
> Cool.  Any comment from the core team on whether this is a possibility?  If 
> it is and nobody else wants to write a proposal I would be willing to do it.

"Throwing Properties and Subscripts" proposal by Brent Royal-Gordon (12 months 
ago):



-- Ben

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Itai Ferber via swift-evolution



On 16 Mar 2017, at 13:27, David Hart wrote:

> On 16 Mar 2017, at 20:55, Itai Ferber via swift-evolution 
 wrote:


I’m going to reply to this thread as a whole — apologies if 
there’s someone’s comment that I’ve missed.


This is something that has come up in internal review, and we’ve 
certainly given it thought. As Zach has already mentioned, the 
primary concern with overloading based on return type is ambiguity.
There are many cases in which Swift’s type system currently does 
not handle ambiguity in the way that you would expect, and it can be 
very surprising. For instance,


func foo() -> Int { return 42 }
func foo() -> Double { return .pi }
func consumesInt(_ x : Int) { print(x) }

let x = foo() // Ambiguous use of foo()
consumesInt(x) // Even though x is going to be used as an Int
let y: Int = x // Same here
let x = foo() as Int works now, but it actually didn’t always — 
until a somewhat recent version of Swift AFAICT, the only way to 
resolve the ambiguity was through let x: Int = foo(). This has since 
been fixed, but it was very confusing to try to figure out the 
unambiguous way to call it.


Keep in mind that this isn’t an unreasonable thing to want to do:

struct Foo {
var x: Int
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: 
CodingKeys.self)


// Want to process an element before it’s assigned.
let x = container.decode(forKey: .x) // Ambiguous call

// Or whatever.
if x < 0 {
self.x = x + 100
else {
self.x = x * 200
}
}
}
You can write let x: Int = container.decode(…) or let x = 
container.decode(…) as Int, but this isn’t always intuitive.



That’s where I disagree. Let me try to prove my point:

You bring up the example of having to store the decoded value in a 
variable before setting it to a typed property. But its also not 
unreasonable to want to do the same thing when encoding the value, 
possibly storing it into a different type. If we follow that argument, 
its also not very intuitive to have to do


container.encode(x as Double, forKey: .x).

Wouldn’t that be an argument to have an API like this:

func encode(_ value: Data?, forKey key: Key, as type: T.Type) 
throws

I don’t agree that these are equivalent cases.

Here, for an `as` cast to be valid, the type of `x` must be an 
existential (I’m guessing `Any`).
The original `container.encode(x, forKey: .x)` call is not ambiguous 
because `x` has no type, but rather because the type of `x` does not 
match any of the overloads. You would get the same error as if you wrote


```swift
struct NonCodableFoo {}
let x = NonCodableFoo()
container.encode(x, forKey: .x)
```

You have to convert the type to something that fits one of the 
overloads.


On encode, there cannot be any true ambiguity because it’s not 
possible to satisfy more than one of these concrete overloads. You 
cannot have a thing with a type which would satisfy both, say, `Int` and 
`Double`.


I would argue that type inference is a core feature in Swift and that 
we should embrace it. I believe that in most cases the return value of 
encode will be stored into a typed property and type inference will do 
the right thing. In the few cases where the type has to be enforced, 
the patterns you mention above are not weird syntax; they are used and 
useful all over Swift:

Sure, but I think these cases are not equivalent.


let cgFloat: CGFloat = 42
42 has a default value of `Int`, but since `CGFloat` is 
`ExpressibleByIntLiteral`, this becomes the equivalent of writing `let 
cfFloat = CGFloat(42)`, which would not be ambiguous without the 
`CGFloat()`; you would just get an `Int`.


With `let x = container.decode(forKey: .x)`, has _has no type_ unless 
otherwise specified.



let pi = 3.14159265359 as Float
Same here, but with `Double` instead of `Int`, and `Float` instead of 
`CGFloat`…


let person = factory.get() // potential feature in Generics 
Manifesto
This isn’t type inference. This is type specification, which is 
exactly what we are trying to do. At the moment, explicit type 
specification has a different syntax: passing a metatype as an argument.


If this feature were available, this is what we would use.

The way I think about it is that the type argument is already there as 
a generic parameter. Adding an extra argument that needs to be 
explicitly given on every single call feels like unneeded verbosity to 
me.
For consideration: why does `let person = factory.get()` seem 
reasonable, but `let person = factory.get(Person.self)` does not?


Consider also that the metatype would also be necessary for 
decode(_ type: Value.Type, forKey: Key) -> Value 
because the return value of that certainly could be ambiguous in many 
cases.


Finally, the metatype arg allows you to express the following 
succinctly: let v: SuperClass = container.decode(SubClass.self, 
forKey: .v).


In the general case (decode) we 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Matthew Johnson via swift-evolution
This is a fantastic proposal!  I am very much looking forward to robust 
Swift-native encoding and decoding in Foundation.  The compiler synthesized 
conformances is especially great!I want to thank everyone who worked on it. 
 It is clear that a lot of work went into the proposal.

The proposal covers a lot of ground so I’m breaking my comments up by topic in 
the order the occur in the proposal.

Encode / Decode only types:

Brent raised the question of decode only types.  Encode only types are also not 
uncommon when an API accepts an argument payload that gets serialized into the 
body of a request. The compiler synthesis feature in the proposal makes 
providing both encoding and decoding easy in common cases but this won’t always 
work as needed.

The obvious alternative is to have Decodable and Encodable protocols which 
Codable refines.  This would allow us to omit a conformance we don’t need when 
it can’t be synthesized.  

Your reply to Brent mentions using `fatalError` to avoid implementing the 
direction that isn't needed.  I think it would be better if the conformance can 
reflect what is actually supported by the type.  Requiring us to write 
`fatalError` as a stub for functionality we don’t need is a design problem IMO. 
 I don’t think the extra protocols are really that big a burden.  They don’t 
add any new functionality and are very easy to understand, especially 
considering the symmetry they would have with the other types you are 
introducing.

Coding Keys:

As others have mentioned, the design of this protocol does not require a value 
of a conforming type to actually be a valid key (it can return nil for both 
`intValue` and `stringValue`).  This seems problematic to me.

In the reply to Brent again you mention throwing and `preconditionFailure` as a 
way to handle incompatible keys.  This also seems problematic to me and feels 
like a design problem. If we really need to support more than one underlying 
key type and some encoders will reject some key types this information should 
be captured in the type system.  An encoder would only vend a keyed container 
for keys it actually supports.  Ideally the conformance of a type’s CodingKeys 
could be leveraged to produce a compiler error if an attempt was made to encode 
this type into an encoder that can’t support its keys.  In general, the idea is 
to produce static errors as close to the origin of the programming mistake as 
possible.  

I would very much prefer that we don’t defer to runtime assertions or thrown 
errors, etc for conditions that could be caught statically at compile time 
given the right design.  Other comments have indicated that static guarantees 
are important to the design (encoders *must* guarantee support of primitives 
specified by the protocols, etc).  Why is a static guarantee of compatible 
coding keys considered less important?

Keyed Containers:

Joe posted raised the topic of the alternative of using manual type erasure for 
the keyed containers rather than abstract classes.  Did you explore this 
direction at all?  It feels like a more natural approach for Swift and as Joe 
noted, it can be designed in such a way that eases migration to existentials in 
the future if that is the “ideal” design (which you mentioned in your response).

Decoding Containers:

returns: A value of the requested type, if present for the given key and 
convertible to the requested type.

Can you elaborate on the details of “convertible to the requested type” means?  
It think this is an important detail for the proposal.  

For example, I would expect numeric values to attempt conversion using the 
SE-0080 failable numeric conversion initializers (decoding JSON was a primary 
motivating use case for that proposal).  If the requested type conforms to 
RawRepresentable and the encoded value can be converted to RawValue (perhaps 
using a failable numeric initializer) I would expect the raw value initializer 
to be used to attempt conversion.  If Swift ever gained a standard mechanism 
for generalized value conversion I would also expect that to be used if a 
conversion is available from the encoded type to the requested type.

If either of those conversions fail I would expect something like an “invalid 
value” error or a “conversion failure” error rather than a “type mismatch” 
error.  The types don’t exactly mismatch, we just have a failable conversion 
process that did not succeed.

Context:

I’m glad Brent raised the topic of supporting multiple formats.  In his example 
the difference was remote and local formats.  I’ve also seen cases where the 
same API requires the same model to be encoded differently in different 
endpoints.  This is awful, but it also happens sometimes in the wild.  
Supporting an application specified encoding context would be very useful for 
handling these situations (the `codingKeyContex` would not always be sufficient 
and would usually not be a good way to determine the required encoding or 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Matthew Johnson via swift-evolution

> On Mar 16, 2017, at 4:18 PM, Philippe Hausler  wrote:
> 
> One point of concern with making the implementations rely on that: it would 
> require any adopter of Codable to be built in swift 4 mode no? it might be 
> valuable to keep the protocol not requiring Swift 4 to aide in incremental 
> migration.

Yes, probably so.  I would be disappointed if we allowed the design of Swift 4 
features to be influenced by Swift 3.1 compatibility.

> 
>> On Mar 16, 2017, at 2:14 PM, Matthew Johnson via swift-evolution 
>> > wrote:
>> 
>> 
>>> On Mar 16, 2017, at 4:12 PM, Itai Ferber >> > wrote:
>>> 
>>> If throwing subscripts made it in the Swift 4 timeframe, then we would 
>>> certainly consider it.
>>> 
>> Cool.  Any comment from the core team on whether this is a possibility?  If 
>> it is and nobody else wants to write a proposal I would be willing to do it.
>>> On 16 Mar 2017, at 13:19, Matthew Johnson wrote:
>>> 
>>> 
 On Mar 16, 2017, at 3:01 PM, Itai Ferber > wrote:
 
 Subscripts, by the way, would not help here, since they cannot throw. 
 decode must be able to throw.
 SR-238 
 ;
  for Apple folks, 28775436.
 
>>> They don’t “help” but they do provide a more natural interface.  If the 
>>> Foundation team feels a more wordy interface is necessary that is ok.
>>> 
>>> I specifically mentioned that they can’t throw yet.  Throwing subscripts 
>>> would make a good companion proposal if they could fit into the Swift 4 
>>> timeframe.  If not, then yes we need a method rather than a subscript.  But 
>>> if we can get throwing subscripts into Swift 4, why not use Swift’s first 
>>> class syntactic support for keyed access to keyed containers?
>>> 
 On 16 Mar 2017, at 11:46, Matthew Johnson via swift-evolution wrote:
 
 
 
> On Mar 16, 2017, at 1:34 PM, Zach Waldowski via swift-evolution 
> > wrote:
> 
> On Thu, Mar 16, 2017, at 02:23 PM, Matthew Johnson via swift-evolution 
> wrote:
>> I don’t have an example but I don’t see a problem either.  There are two 
>> options for specifying the return type manually.  We can use the 
>> signature you used above and use `as` to specify the expected type:
>> 
>> let i = decode(.myKey) as Int
> 
> The awkwardness of this syntax is exactly what I'm referring to. Would a 
> beginner know to use "as Int" or ": Int"? Why would they? The 
> "prettiness" of the simple case doesn't make up for how difficult it is 
> to understand and fix its failure cases.
> 
> Any official Swift or Foundation API shouldn't, or shouldn't need to, 
> make use of "tricky" syntax.
 
 I don’t think this is especially tricky.  Nevertheless, we can avoid 
 requiring this syntax by moving the type argument to the end and providing 
 a default.  But I think return type inference is worth supporting.  It has 
 become widely adopted by the community already in this use case.
 
> 
>> If we don’t support this in Foundation we will continue to see 3rd party 
>> libraries that do this.
> 
> The proposal's been out for less than 24 hours, is it really productive 
> to already be taking our ball and go home over such a minor thing?
 
 I don’t think that’s what I’m doing at all.  This is a fantastic proposal. 
  I’m still working through it and writing up my more detailed thoughts.
 
 That said, as with many (most?) first drafts, there is room for 
 improvement.  I think it’s worth pointing out the syntax that many of us 
 would like to use for decoding and at least considering including it in 
 the proposal.  If the answer is that it’s trivial for those who want to 
 use subscripts to write the wrappers for return type inference and / or 
 subscripts themselves that’s ok.  But it’s a fair topic for discussion and 
 should at least be addressed as an alternative that was rejected for a 
 specific reason.
 
> 
> Zach Waldowski
> z...@waldowski.me 
> 
> 
> 
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org 
> https://lists.swift.org/mailman/listinfo/swift-evolution 
> 
 
 ___
 swift-evolution mailing list
 swift-evolution@swift.org 
 https://lists.swift.org/mailman/listinfo/swift-evolution 
 
>>> 
>> 
>> 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Philippe Hausler via swift-evolution
One point of concern with making the implementations rely on that: it would 
require any adopter of Codable to be built in swift 4 mode no? it might be 
valuable to keep the protocol not requiring Swift 4 to aide in incremental 
migration.

> On Mar 16, 2017, at 2:14 PM, Matthew Johnson via swift-evolution 
>  wrote:
> 
> 
>> On Mar 16, 2017, at 4:12 PM, Itai Ferber > > wrote:
>> 
>> If throwing subscripts made it in the Swift 4 timeframe, then we would 
>> certainly consider it.
>> 
> Cool.  Any comment from the core team on whether this is a possibility?  If 
> it is and nobody else wants to write a proposal I would be willing to do it.
>> On 16 Mar 2017, at 13:19, Matthew Johnson wrote:
>> 
>> 
>>> On Mar 16, 2017, at 3:01 PM, Itai Ferber >> > wrote:
>>> 
>>> Subscripts, by the way, would not help here, since they cannot throw. 
>>> decode must be able to throw.
>>> SR-238 
>>> ;
>>>  for Apple folks, 28775436.
>>> 
>> They don’t “help” but they do provide a more natural interface.  If the 
>> Foundation team feels a more wordy interface is necessary that is ok.
>> 
>> I specifically mentioned that they can’t throw yet.  Throwing subscripts 
>> would make a good companion proposal if they could fit into the Swift 4 
>> timeframe.  If not, then yes we need a method rather than a subscript.  But 
>> if we can get throwing subscripts into Swift 4, why not use Swift’s first 
>> class syntactic support for keyed access to keyed containers?
>> 
>>> On 16 Mar 2017, at 11:46, Matthew Johnson via swift-evolution wrote:
>>> 
>>> 
>>> 
 On Mar 16, 2017, at 1:34 PM, Zach Waldowski via swift-evolution 
 > wrote:
 
 On Thu, Mar 16, 2017, at 02:23 PM, Matthew Johnson via swift-evolution 
 wrote:
> I don’t have an example but I don’t see a problem either.  There are two 
> options for specifying the return type manually.  We can use the 
> signature you used above and use `as` to specify the expected type:
> 
> let i = decode(.myKey) as Int
 
 The awkwardness of this syntax is exactly what I'm referring to. Would a 
 beginner know to use "as Int" or ": Int"? Why would they? The "prettiness" 
 of the simple case doesn't make up for how difficult it is to understand 
 and fix its failure cases.
 
 Any official Swift or Foundation API shouldn't, or shouldn't need to, make 
 use of "tricky" syntax.
>>> 
>>> I don’t think this is especially tricky.  Nevertheless, we can avoid 
>>> requiring this syntax by moving the type argument to the end and providing 
>>> a default.  But I think return type inference is worth supporting.  It has 
>>> become widely adopted by the community already in this use case.
>>> 
 
> If we don’t support this in Foundation we will continue to see 3rd party 
> libraries that do this.
 
 The proposal's been out for less than 24 hours, is it really productive to 
 already be taking our ball and go home over such a minor thing?
>>> 
>>> I don’t think that’s what I’m doing at all.  This is a fantastic proposal.  
>>> I’m still working through it and writing up my more detailed thoughts.
>>> 
>>> That said, as with many (most?) first drafts, there is room for 
>>> improvement.  I think it’s worth pointing out the syntax that many of us 
>>> would like to use for decoding and at least considering including it in the 
>>> proposal.  If the answer is that it’s trivial for those who want to use 
>>> subscripts to write the wrappers for return type inference and / or 
>>> subscripts themselves that’s ok.  But it’s a fair topic for discussion and 
>>> should at least be addressed as an alternative that was rejected for a 
>>> specific reason.
>>> 
 
 Zach Waldowski
 z...@waldowski.me 
 
 
 
 
 ___
 swift-evolution mailing list
 swift-evolution@swift.org 
 https://lists.swift.org/mailman/listinfo/swift-evolution 
 
>>> 
>>> ___
>>> swift-evolution mailing list
>>> swift-evolution@swift.org 
>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>> 
>> 
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Matthew Johnson via swift-evolution

> On Mar 16, 2017, at 4:12 PM, Itai Ferber  wrote:
> 
> If throwing subscripts made it in the Swift 4 timeframe, then we would 
> certainly consider it.
> 
Cool.  Any comment from the core team on whether this is a possibility?  If it 
is and nobody else wants to write a proposal I would be willing to do it.
> On 16 Mar 2017, at 13:19, Matthew Johnson wrote:
> 
> 
>> On Mar 16, 2017, at 3:01 PM, Itai Ferber > > wrote:
>> 
>> Subscripts, by the way, would not help here, since they cannot throw. decode 
>> must be able to throw.
>> SR-238 
>> ;
>>  for Apple folks, 28775436.
>> 
> They don’t “help” but they do provide a more natural interface.  If the 
> Foundation team feels a more wordy interface is necessary that is ok.
> 
> I specifically mentioned that they can’t throw yet.  Throwing subscripts 
> would make a good companion proposal if they could fit into the Swift 4 
> timeframe.  If not, then yes we need a method rather than a subscript.  But 
> if we can get throwing subscripts into Swift 4, why not use Swift’s first 
> class syntactic support for keyed access to keyed containers?
> 
>> On 16 Mar 2017, at 11:46, Matthew Johnson via swift-evolution wrote:
>> 
>> 
>> 
>>> On Mar 16, 2017, at 1:34 PM, Zach Waldowski via swift-evolution 
>>> > wrote:
>>> 
>>> On Thu, Mar 16, 2017, at 02:23 PM, Matthew Johnson via swift-evolution 
>>> wrote:
 I don’t have an example but I don’t see a problem either.  There are two 
 options for specifying the return type manually.  We can use the signature 
 you used above and use `as` to specify the expected type:
 
 let i = decode(.myKey) as Int
>>> 
>>> The awkwardness of this syntax is exactly what I'm referring to. Would a 
>>> beginner know to use "as Int" or ": Int"? Why would they? The "prettiness" 
>>> of the simple case doesn't make up for how difficult it is to understand 
>>> and fix its failure cases.
>>> 
>>> Any official Swift or Foundation API shouldn't, or shouldn't need to, make 
>>> use of "tricky" syntax.
>> 
>> I don’t think this is especially tricky.  Nevertheless, we can avoid 
>> requiring this syntax by moving the type argument to the end and providing a 
>> default.  But I think return type inference is worth supporting.  It has 
>> become widely adopted by the community already in this use case.
>> 
>>> 
 If we don’t support this in Foundation we will continue to see 3rd party 
 libraries that do this.
>>> 
>>> The proposal's been out for less than 24 hours, is it really productive to 
>>> already be taking our ball and go home over such a minor thing?
>> 
>> I don’t think that’s what I’m doing at all.  This is a fantastic proposal.  
>> I’m still working through it and writing up my more detailed thoughts.
>> 
>> That said, as with many (most?) first drafts, there is room for improvement. 
>>  I think it’s worth pointing out the syntax that many of us would like to 
>> use for decoding and at least considering including it in the proposal.  If 
>> the answer is that it’s trivial for those who want to use subscripts to 
>> write the wrappers for return type inference and / or subscripts themselves 
>> that’s ok.  But it’s a fair topic for discussion and should at least be 
>> addressed as an alternative that was rejected for a specific reason.
>> 
>>> 
>>> Zach Waldowski
>>> z...@waldowski.me 
>>> 
>>> 
>>> 
>>> 
>>> ___
>>> swift-evolution mailing list
>>> swift-evolution@swift.org 
>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>> 
>> 
>> ___
>> swift-evolution mailing list
>> swift-evolution@swift.org 
>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>> 
> 

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Itai Ferber via swift-evolution
If throwing subscripts made it in the Swift 4 timeframe, then we would 
certainly consider it.


On 16 Mar 2017, at 13:19, Matthew Johnson wrote:


> On Mar 16, 2017, at 3:01 PM, Itai Ferber  wrote:


Subscripts, by the way, would not help here, since they cannot throw. 
decode must be able to throw.
SR-238 
; 
for Apple folks, 28775436.


They don’t “help” but they do provide a more natural interface.  
If the Foundation team feels a more wordy interface is necessary that 
is ok.


I specifically mentioned that they can’t throw yet.  Throwing 
subscripts would make a good companion proposal if they could fit into 
the Swift 4 timeframe.  If not, then yes we need a method rather than 
a subscript.  But if we can get throwing subscripts into Swift 4, why 
not use Swift’s first class syntactic support for keyed access to 
keyed containers?



On 16 Mar 2017, at 11:46, Matthew Johnson via swift-evolution wrote:



On Mar 16, 2017, at 1:34 PM, Zach Waldowski via swift-evolution 
> 
wrote:


On Thu, Mar 16, 2017, at 02:23 PM, Matthew Johnson via 
swift-evolution wrote:
I don’t have an example but I don’t see a problem either.  
There are two options for specifying the return type manually.  We 
can use the signature you used above and use `as` to specify the 
expected type:


let i = decode(.myKey) as Int


The awkwardness of this syntax is exactly what I'm referring to. 
Would a beginner know to use "as Int" or ": Int"? Why would they? 
The "prettiness" of the simple case doesn't make up for how 
difficult it is to understand and fix its failure cases.


Any official Swift or Foundation API shouldn't, or shouldn't need 
to, make use of "tricky" syntax.


I don’t think this is especially tricky.  Nevertheless, we can 
avoid requiring this syntax by moving the type argument to the end 
and providing a default.  But I think return type inference is worth 
supporting.  It has become widely adopted by the community already in 
this use case.




If we don’t support this in Foundation we will continue to see 
3rd party libraries that do this.


The proposal's been out for less than 24 hours, is it really 
productive to already be taking our ball and go home over such a 
minor thing?


I don’t think that’s what I’m doing at all.  This is a 
fantastic proposal.  I’m still working through it and writing up my 
more detailed thoughts.


That said, as with many (most?) first drafts, there is room for 
improvement.  I think it’s worth pointing out the syntax that many 
of us would like to use for decoding and at least considering 
including it in the proposal.  If the answer is that it’s trivial 
for those who want to use subscripts to write the wrappers for return 
type inference and / or subscripts themselves that’s ok.  But 
it’s a fair topic for discussion and should at least be addressed 
as an alternative that was rejected for a specific reason.




Zach Waldowski
z...@waldowski.me 




___
swift-evolution mailing list
swift-evolution@swift.org 
https://lists.swift.org/mailman/listinfo/swift-evolution


___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution 




___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Itai Ferber via swift-evolution

Hi Slava,

Thanks for your comments!

On 16 Mar 2017, at 13:50, Slava Pestov wrote:


Hi Itai,

I’m wondering what the motivation is for keeping this as part of 
Foundation and not the standard library. It seems like you’re 
landing an implementation of this in the Foundation overlay on master, 
and another copy of all the code will have to go into 
swift-corelibs-foundation. This seems suboptimal. Or are there future 
plans to unify the Foundation overlay with corelibs-foundation 
somehow?
This has to be part of Foundation because `Data`, a Foundation type, is 
one of the primitive types of serialization. This will be doubly true if 
we decide to add `Date` as another primitive type.


I agree that this is suboptimal at the moment, but we will work to find 
a way to keep the work in sync in a reasonable manner.


Also the implementation uses some Foundation-isms (NSMutableArray, 
NSNumber) and it would be nice to stick with idiomatic Swift as much 
as possible instead.

Using the Foundation framework is just as idiomatic in Swift… ;)
In this specific case, we need collections with reference semantics 
(`NSMutableArray` and `NSMutableDictionary`) and a concrete type-erased 
number box (`NSNumber`); theres’s no reason to reinvent the wheel if 
we already have exactly the tools we need.


The reference implementation at the moment goes through 
`JSONSerialization`, which affects the specifics of its implementation. 
This may change in the future.


Finally you should take a look at the integer protocol work 
(https://github.com/apple/swift-evolution/blob/master/proposals/0104-improved-integers.md 
) 
to replace the repetitive code surrounding primitive types, however I 
don’t know if this has landed in master yet.
As mentioned in other emails, the list of primitive types was carefully 
chosen because we need to have a concrete list of types which consumers 
can rely on being supported, and that `Encoder`s and `Decoder`s know 
they _must_ support.


Specifically:

1. For binary formats, the difference between an `Int16` and an `Int64` 
is significant. The `Encoder` would need to know that it’s received 
one type or another, not just a `FixedWidthInteger`; this would involve 
a runtime check of the concrete type of the argument
2. Any type can conform to these protocols — nothing is preventing me 
from writing an `Int37` type conforming to `FixedWidthInteger` and 
passing it in. Most encoders would really not know what to do with this 
type (especially ones with binary formats), but the failure would be a 
runtime one instead of a static one
  * A concrete example of this is the `FloatingPoint` protocol. 
`Float80` conforms to the protocol, but no common binary format I’ve 
seen supports 80-bit floating-point values. We’d prefer to prevent 
that statically by accepting only `Float` and `Double`
3. Consumers of the API then have no guarantees that a specific 
`Encoder` supports the type that they need. Did the encoder remember to 
support `UInt64` values? Similarly, `Encoder`s and `Decoder`s don’t 
know what types they need to be considering. Am I supposed to handle 
`UInt8` differently from `Int16`? With a list of concrete types, this 
becomes immediately clear — both consumers and writers of `Encoder`s 
have a clear contract.




Slava



___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Tony Parker via swift-evolution
Hi Slava,

> On Mar 16, 2017, at 1:50 PM, Slava Pestov via swift-evolution 
>  wrote:
> 
> Hi Itai,
> 
> I’m wondering what the motivation is for keeping this as part of Foundation 
> and not the standard library. It seems like you’re landing an implementation 
> of this in the Foundation overlay on master, and another copy of all the code 
> will have to go into swift-corelibs-foundation. This seems suboptimal. Or are 
> there future plans to unify the Foundation overlay with corelibs-foundation 
> somehow?

I would like some unification in the future, but they are currently two 
separate implementations for a bunch of reasons (lack of bridging on Linux 
being a huge one, along with the inability of the standard library and runtime 
to distinguish between presence of Objective-C and the presence of Foundation).

> 
> Also the implementation uses some Foundation-isms (NSMutableArray, NSNumber) 
> and it would be nice to stick with idiomatic Swift as much as possible 
> instead.
> 

The implementation you’re looking at is for JSONArchiver, which is based on 
NSJSONSerialization, which is part of Foundation and not the standard library. 
That’s a primary reason to use Foundation. NSJSONSerialization also deals with 
types like ‘Date’ which are in Foundation. Finally, the primitive Coding API 
uses Data, which is a Foundation type.

So in summary, I’m fine with this API being part of Foundation. Foundation is 
available the same places the standard library is, so it is more than 
acceptable to use Foundation API and types here.

- Tony

> Finally you should take a look at the integer protocol work 
> (https://github.com/apple/swift-evolution/blob/master/proposals/0104-improved-integers.md
>  
> )
>  to replace the repetitive code surrounding primitive types, however I don’t 
> know if this has landed in master yet.
> 
> Slava
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Matthew Johnson via swift-evolution

> On Mar 16, 2017, at 3:27 PM, David Hart  wrote:
> 
> 
>> On 16 Mar 2017, at 20:55, Itai Ferber via swift-evolution 
>> > wrote:
>> 
>> I’m going to reply to this thread as a whole — apologies if there’s 
>> someone’s comment that I’ve missed.
>> 
>> This is something that has come up in internal review, and we’ve certainly 
>> given it thought. As Zach has already mentioned, the primary concern with 
>> overloading based on return type is ambiguity.
>> There are many cases in which Swift’s type system currently does not handle 
>> ambiguity in the way that you would expect, and it can be very surprising. 
>> For instance,
>> 
>> func foo() -> Int { return 42 }
>> func foo() -> Double { return .pi }
>> func consumesInt(_ x : Int) { print(x) }
>> 
>> let x = foo() // Ambiguous use of foo()
>> consumesInt(x) // Even though x is going to be used as an Int
>> let y: Int = x // Same here
>> let x = foo() as Int works now, but it actually didn’t always — until a 
>> somewhat recent version of Swift AFAICT, the only way to resolve the 
>> ambiguity was through let x: Int = foo(). This has since been fixed, but it 
>> was very confusing to try to figure out the unambiguous way to call it.
>> 
>> Keep in mind that this isn’t an unreasonable thing to want to do:
>> 
>> struct Foo {
>> var x: Int
>> init(from decoder: Decoder) throws {
>> let container = try decoder.container(keyedBy: CodingKeys.self)
>> 
>> // Want to process an element before it’s assigned.
>> let x = container.decode(forKey: .x) // Ambiguous call
>> 
>> // Or whatever.
>> if x < 0 {
>> self.x = x + 100
>> else {
>> self.x = x * 200
>> }
>> }
>> }
>> You can write let x: Int = container.decode(…) or let x = 
>> container.decode(…) as Int, but this isn’t always intuitive.
>> 
> That’s where I disagree. Let me try to prove my point:
> 
> You bring up the example of having to store the decoded value in a variable 
> before setting it to a typed property. But its also not unreasonable to want 
> to do the same thing when encoding the value, possibly storing it into a 
> different type. If we follow that argument, its also not very intuitive to 
> have to do
> 
> container.encode(x as Double, forKey: .x).
> 
> Wouldn’t that be an argument to have an API like this:
> 
> func encode(_ value: Data?, forKey key: Key, as type: T.Type) throws
> 
> I would argue that type inference is a core feature in Swift and that we 
> should embrace it. I believe that in most cases the return value of encode 
> will be stored into a typed property and type inference will do the right 
> thing. In the few cases where the type has to be enforced, the patterns you 
> mention above are not weird syntax; they are used and useful all over Swift:
> 
> let cgFloat: CGFloat = 42
> let pi = 3.14159265359 as Float
> let person = factory.get() // potential feature in Generics Manifesto
> 
> The way I think about it is that the type argument is already there as a 
> generic parameter. Adding an extra argument that needs to be explicitly given 
> on every single call feels like unneeded verbosity to me.

I agree with everything David says here.

>> Consider also that the metatype would also be necessary for decode> Codable>(_ type: Value.Type, forKey: Key) -> Value because the return value 
>> of that certainly could be ambiguous in many cases.
>> 
>> Finally, the metatype arg allows you to express the following succinctly: 
>> let v: SuperClass = container.decode(SubClass.self, forKey: .v).
>> 
>> In the general case (decode) we would need the metatype to 
>> avoid ambiguity. It’s not strictly necessary for primitive types, but helps 
>> in the case of ambiguity, and solves the conceptual overhead of "Why do I 
>> specify the type sometimes but not others? Why are some of these types 
>> special? Should I always provide the type? Why wouldn’t I?"
>> 
>> Matthew offered func decode(_ key: Key, as type: T.Type = T.self) throws 
>> -> T which looks appealing, but:
>> 
>> Doesn’t help resolve the ambiguity either
>> Allows for 3 ways of expressing the same thing (let x: Int = decode(key), 
>> let x = decode(key) as Int, and let x = decode(key, as: Int.self))
>> The cognitive overhead of figuring out all of the ambiguity goes away when 
>> we’re consistent everywhere.
>> FWIW, too, I am not convinced that Foundation should add API just because 
>> 3rd parties will add it.
>> 
> Agreed. Foundation should not add API just because 3rd parties do it. But 3rd 
> parties should not be dismissed entirely nonetheless. They are a good 
> breeding ground for ideas to spawn and shape Swift in interesting ways.

+1.  The point is not that we should do everything 3rd parties do.  But we 
should also not leave a gap in Foundation where the community has identified a 
lighter syntactic approach that has been used successfully in 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Slava Pestov via swift-evolution
Hi Itai,

I’m wondering what the motivation is for keeping this as part of Foundation and 
not the standard library. It seems like you’re landing an implementation of 
this in the Foundation overlay on master, and another copy of all the code will 
have to go into swift-corelibs-foundation. This seems suboptimal. Or are there 
future plans to unify the Foundation overlay with corelibs-foundation somehow?

Also the implementation uses some Foundation-isms (NSMutableArray, NSNumber) 
and it would be nice to stick with idiomatic Swift as much as possible instead.

Finally you should take a look at the integer protocol work 
(https://github.com/apple/swift-evolution/blob/master/proposals/0104-improved-integers.md
 
)
 to replace the repetitive code surrounding primitive types, however I don’t 
know if this has landed in master yet.

Slava___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Matthew Johnson via swift-evolution

> On Mar 16, 2017, at 3:27 PM, Tony Parker  wrote:
> 
> 
>> On Mar 16, 2017, at 1:24 PM, Matthew Johnson via swift-evolution 
>> > wrote:
>> 
>>> 
>>> On Mar 16, 2017, at 2:58 PM, David Hart via swift-evolution 
>>> > wrote:
>>> 
>>> 
 On 16 Mar 2017, at 19:34, Zach Waldowski via swift-evolution 
 > wrote:
 
 On Thu, Mar 16, 2017, at 02:23 PM, Matthew Johnson via swift-evolution 
 wrote:
> I don’t have an example but I don’t see a problem either.  There are two 
> options for specifying the return type manually.  We can use the 
> signature you used above and use `as` to specify the expected type:
> 
> let i = decode(.myKey) as Int
 
 The awkwardness of this syntax is exactly what I'm referring to. Would a 
 beginner know to use "as Int" or ": Int"? Why would they? The "prettiness" 
 of the simple case doesn't make up for how difficult it is to understand 
 and fix its failure cases.
 
 Any official Swift or Foundation API shouldn't, or shouldn't need to, make 
 use of "tricky" syntax.
>>> 
>>> Two arguments:
>>> 
>>> 1) Most of the time, you will be setting the return value of decode into a 
>>> typed property and will not need ‘as’.
>>> 2) Even when you do need it, its not tricky syntax: it’s the official way 
>>> to direct the type inference engine in Swift.
>> 
>> +1 to both of David’s points.  Needing to explicitly resolve ambiguity 
>> during decoding is pretty rare.  When necessary the syntax is perfectly 
>> reasonable.  Swift users who don’t understand single statement inference 
>> works and how to guide the inference engine should learn about these topics 
>> sooner or later.  It won’t be a hard topic to search if a user runs into 
>> trouble either.  
>> 
>> Nevertheless, if the Foundation team is strongly opposed to this many of us 
>> will just write our own wrappers.  This isn’t hard but it makes Swift code 
>> less consistent throughout the community.  Supporting consistent usage 
>> throughout the community seems like a reasonable goal to me.  IMO that means 
>> not leaving obvious expressivity gaps that are easy to fill.  In this case, 
>> there is a very good reason why we prefer subscripts and return type 
>> inference.  It makes our code much more clear by omitting a bunch of 
>> needless and noisy words (which is one of the principles of the API Design 
>> Guidelines).
>> 
> 
> Hi Matthew,
> 
> While fully acknowledging that the proposed API adds some “wordiness", I 
> would also like to point out that the Swift API guidelines also explicitly 
> state a goal to avoid overloading on return type:
> 
> "Lastly, avoid “overloading on return type” because it causes ambiguities in 
> the presence of type inference.”

Fair enough.  I think that’s *usually* a great guideline.  However, in this 
specific use case I strongly support return type inference as a design that 
increases clarity while ambiguity is very rare in practice.  In any case, it 
sounds like the Foundation team has a pretty firm opinion on this topic.  I’ve 
offered my two cents and will let it drop now. :)

> 
> - Tony
> 
>>> David.
>>> 
> If we don’t support this in Foundation we will continue to see 3rd party 
> libraries that do this.
 
 The proposal's been out for less than 24 hours, is it really productive to 
 already be taking our ball and go home over such a minor thing?
 
 Zach Waldowski
 z...@waldowski.me 
 
 
 
 
 ___
 swift-evolution mailing list
 swift-evolution@swift.org 
 https://lists.swift.org/mailman/listinfo/swift-evolution 
 
>>> 
>>> ___
>>> swift-evolution mailing list
>>> swift-evolution@swift.org 
>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>> 
>> 
>> ___
>> swift-evolution mailing list
>> swift-evolution@swift.org 
>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>> 

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread David Hart via swift-evolution

> On 16 Mar 2017, at 20:55, Itai Ferber via swift-evolution 
>  wrote:
> 
> I’m going to reply to this thread as a whole — apologies if there’s someone’s 
> comment that I’ve missed.
> 
> This is something that has come up in internal review, and we’ve certainly 
> given it thought. As Zach has already mentioned, the primary concern with 
> overloading based on return type is ambiguity.
> There are many cases in which Swift’s type system currently does not handle 
> ambiguity in the way that you would expect, and it can be very surprising. 
> For instance,
> 
> func foo() -> Int { return 42 }
> func foo() -> Double { return .pi }
> func consumesInt(_ x : Int) { print(x) }
> 
> let x = foo() // Ambiguous use of foo()
> consumesInt(x) // Even though x is going to be used as an Int
> let y: Int = x // Same here
> let x = foo() as Int works now, but it actually didn’t always — until a 
> somewhat recent version of Swift AFAICT, the only way to resolve the 
> ambiguity was through let x: Int = foo(). This has since been fixed, but it 
> was very confusing to try to figure out the unambiguous way to call it.
> 
> Keep in mind that this isn’t an unreasonable thing to want to do:
> 
> struct Foo {
> var x: Int
> init(from decoder: Decoder) throws {
> let container = try decoder.container(keyedBy: CodingKeys.self)
> 
> // Want to process an element before it’s assigned.
> let x = container.decode(forKey: .x) // Ambiguous call
> 
> // Or whatever.
> if x < 0 {
> self.x = x + 100
> else {
> self.x = x * 200
> }
> }
> }
> You can write let x: Int = container.decode(…) or let x = container.decode(…) 
> as Int, but this isn’t always intuitive.
> 
That’s where I disagree. Let me try to prove my point:

You bring up the example of having to store the decoded value in a variable 
before setting it to a typed property. But its also not unreasonable to want to 
do the same thing when encoding the value, possibly storing it into a different 
type. If we follow that argument, its also not very intuitive to have to do

container.encode(x as Double, forKey: .x).

Wouldn’t that be an argument to have an API like this:

func encode(_ value: Data?, forKey key: Key, as type: T.Type) throws

I would argue that type inference is a core feature in Swift and that we should 
embrace it. I believe that in most cases the return value of encode will be 
stored into a typed property and type inference will do the right thing. In the 
few cases where the type has to be enforced, the patterns you mention above are 
not weird syntax; they are used and useful all over Swift:

let cgFloat: CGFloat = 42
let pi = 3.14159265359 as Float
let person = factory.get() // potential feature in Generics Manifesto

The way I think about it is that the type argument is already there as a 
generic parameter. Adding an extra argument that needs to be explicitly given 
on every single call feels like unneeded verbosity to me.
> Consider also that the metatype would also be necessary for decode Codable>(_ type: Value.Type, forKey: Key) -> Value because the return value 
> of that certainly could be ambiguous in many cases.
> 
> Finally, the metatype arg allows you to express the following succinctly: let 
> v: SuperClass = container.decode(SubClass.self, forKey: .v).
> 
> In the general case (decode) we would need the metatype to 
> avoid ambiguity. It’s not strictly necessary for primitive types, but helps 
> in the case of ambiguity, and solves the conceptual overhead of "Why do I 
> specify the type sometimes but not others? Why are some of these types 
> special? Should I always provide the type? Why wouldn’t I?"
> 
> Matthew offered func decode(_ key: Key, as type: T.Type = T.self) throws 
> -> T which looks appealing, but:
> 
> Doesn’t help resolve the ambiguity either
> Allows for 3 ways of expressing the same thing (let x: Int = decode(key), let 
> x = decode(key) as Int, and let x = decode(key, as: Int.self))
> The cognitive overhead of figuring out all of the ambiguity goes away when 
> we’re consistent everywhere.
> FWIW, too, I am not convinced that Foundation should add API just because 3rd 
> parties will add it.
> 
Agreed. Foundation should not add API just because 3rd parties do it. But 3rd 
parties should not be dismissed entirely nonetheless. They are a good breeding 
ground for ideas to spawn and shape Swift in interesting ways.
> The ambiguity in the general case cannot be solved by wrappers, and I would 
> prefer to provide one simple, consistent solution; if 3rd parties would like 
> to add wrappers for their own sake, then I certainly encourage that.
> 
> On 16 Mar 2017, at 11:46, Matthew Johnson via swift-evolution wrote:
> 
> 
> 
>> On Mar 16, 2017, at 1:34 PM, Zach Waldowski via swift-evolution 
>> > wrote:
>> 
>> On Thu, Mar 16, 2017, at 02:23 PM, Matthew 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Tony Parker via swift-evolution

> On Mar 16, 2017, at 1:24 PM, Matthew Johnson via swift-evolution 
>  wrote:
> 
>> 
>> On Mar 16, 2017, at 2:58 PM, David Hart via swift-evolution 
>> > wrote:
>> 
>> 
>>> On 16 Mar 2017, at 19:34, Zach Waldowski via swift-evolution 
>>> > wrote:
>>> 
>>> On Thu, Mar 16, 2017, at 02:23 PM, Matthew Johnson via swift-evolution 
>>> wrote:
 I don’t have an example but I don’t see a problem either.  There are two 
 options for specifying the return type manually.  We can use the signature 
 you used above and use `as` to specify the expected type:
 
 let i = decode(.myKey) as Int
>>> 
>>> The awkwardness of this syntax is exactly what I'm referring to. Would a 
>>> beginner know to use "as Int" or ": Int"? Why would they? The "prettiness" 
>>> of the simple case doesn't make up for how difficult it is to understand 
>>> and fix its failure cases.
>>> 
>>> Any official Swift or Foundation API shouldn't, or shouldn't need to, make 
>>> use of "tricky" syntax.
>> 
>> Two arguments:
>> 
>> 1) Most of the time, you will be setting the return value of decode into a 
>> typed property and will not need ‘as’.
>> 2) Even when you do need it, its not tricky syntax: it’s the official way to 
>> direct the type inference engine in Swift.
> 
> +1 to both of David’s points.  Needing to explicitly resolve ambiguity during 
> decoding is pretty rare.  When necessary the syntax is perfectly reasonable.  
> Swift users who don’t understand single statement inference works and how to 
> guide the inference engine should learn about these topics sooner or later.  
> It won’t be a hard topic to search if a user runs into trouble either.  
> 
> Nevertheless, if the Foundation team is strongly opposed to this many of us 
> will just write our own wrappers.  This isn’t hard but it makes Swift code 
> less consistent throughout the community.  Supporting consistent usage 
> throughout the community seems like a reasonable goal to me.  IMO that means 
> not leaving obvious expressivity gaps that are easy to fill.  In this case, 
> there is a very good reason why we prefer subscripts and return type 
> inference.  It makes our code much more clear by omitting a bunch of needless 
> and noisy words (which is one of the principles of the API Design Guidelines).
> 

Hi Matthew,

While fully acknowledging that the proposed API adds some “wordiness", I would 
also like to point out that the Swift API guidelines also explicitly state a 
goal to avoid overloading on return type:

"Lastly, avoid “overloading on return type” because it causes ambiguities in 
the presence of type inference.”

- Tony

>> David.
>> 
 If we don’t support this in Foundation we will continue to see 3rd party 
 libraries that do this.
>>> 
>>> The proposal's been out for less than 24 hours, is it really productive to 
>>> already be taking our ball and go home over such a minor thing?
>>> 
>>> Zach Waldowski
>>> z...@waldowski.me 
>>> 
>>> 
>>> 
>>> 
>>> ___
>>> swift-evolution mailing list
>>> swift-evolution@swift.org 
>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>> 
>> 
>> ___
>> swift-evolution mailing list
>> swift-evolution@swift.org 
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org 
> https://lists.swift.org/mailman/listinfo/swift-evolution 
> 
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Matthew Johnson via swift-evolution

> On Mar 16, 2017, at 2:58 PM, David Hart via swift-evolution 
>  wrote:
> 
> 
>> On 16 Mar 2017, at 19:34, Zach Waldowski via swift-evolution 
>> > wrote:
>> 
>> On Thu, Mar 16, 2017, at 02:23 PM, Matthew Johnson via swift-evolution wrote:
>>> I don’t have an example but I don’t see a problem either.  There are two 
>>> options for specifying the return type manually.  We can use the signature 
>>> you used above and use `as` to specify the expected type:
>>> 
>>> let i = decode(.myKey) as Int
>> 
>> The awkwardness of this syntax is exactly what I'm referring to. Would a 
>> beginner know to use "as Int" or ": Int"? Why would they? The "prettiness" 
>> of the simple case doesn't make up for how difficult it is to understand and 
>> fix its failure cases.
>> 
>> Any official Swift or Foundation API shouldn't, or shouldn't need to, make 
>> use of "tricky" syntax.
> 
> Two arguments:
> 
> 1) Most of the time, you will be setting the return value of decode into a 
> typed property and will not need ‘as’.
> 2) Even when you do need it, its not tricky syntax: it’s the official way to 
> direct the type inference engine in Swift.

+1 to both of David’s points.  Needing to explicitly resolve ambiguity during 
decoding is pretty rare.  When necessary the syntax is perfectly reasonable.  
Swift users who don’t understand single statement inference works and how to 
guide the inference engine should learn about these topics sooner or later.  It 
won’t be a hard topic to search if a user runs into trouble either.  

Nevertheless, if the Foundation team is strongly opposed to this many of us 
will just write our own wrappers.  This isn’t hard but it makes Swift code less 
consistent throughout the community.  Supporting consistent usage throughout 
the community seems like a reasonable goal to me.  IMO that means not leaving 
obvious expressivity gaps that are easy to fill.  In this case, there is a very 
good reason why we prefer subscripts and return type inference.  It makes our 
code much more clear by omitting a bunch of needless and noisy words (which is 
one of the principles of the API Design Guidelines).

> 
> David.
> 
>>> If we don’t support this in Foundation we will continue to see 3rd party 
>>> libraries that do this.
>> 
>> The proposal's been out for less than 24 hours, is it really productive to 
>> already be taking our ball and go home over such a minor thing?
>> 
>> Zach Waldowski
>> z...@waldowski.me 
>> 
>> 
>> 
>> 
>> ___
>> swift-evolution mailing list
>> swift-evolution@swift.org 
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Matthew Johnson via swift-evolution

> On Mar 16, 2017, at 3:01 PM, Itai Ferber  wrote:
> 
> Subscripts, by the way, would not help here, since they cannot throw. decode 
> must be able to throw.
> SR-238 
> ;
>  for Apple folks, 28775436.
> 
They don’t “help” but they do provide a more natural interface.  If the 
Foundation team feels a more wordy interface is necessary that is ok.

I specifically mentioned that they can’t throw yet.  Throwing subscripts would 
make a good companion proposal if they could fit into the Swift 4 timeframe.  
If not, then yes we need a method rather than a subscript.  But if we can get 
throwing subscripts into Swift 4, why not use Swift’s first class syntactic 
support for keyed access to keyed containers?

> On 16 Mar 2017, at 11:46, Matthew Johnson via swift-evolution wrote:
> 
> 
> 
>> On Mar 16, 2017, at 1:34 PM, Zach Waldowski via swift-evolution 
>> > wrote:
>> 
>> On Thu, Mar 16, 2017, at 02:23 PM, Matthew Johnson via swift-evolution wrote:
>>> I don’t have an example but I don’t see a problem either.  There are two 
>>> options for specifying the return type manually.  We can use the signature 
>>> you used above and use `as` to specify the expected type:
>>> 
>>> let i = decode(.myKey) as Int
>> 
>> The awkwardness of this syntax is exactly what I'm referring to. Would a 
>> beginner know to use "as Int" or ": Int"? Why would they? The "prettiness" 
>> of the simple case doesn't make up for how difficult it is to understand and 
>> fix its failure cases.
>> 
>> Any official Swift or Foundation API shouldn't, or shouldn't need to, make 
>> use of "tricky" syntax.
> 
> I don’t think this is especially tricky.  Nevertheless, we can avoid 
> requiring this syntax by moving the type argument to the end and providing a 
> default.  But I think return type inference is worth supporting.  It has 
> become widely adopted by the community already in this use case.
> 
>> 
>>> If we don’t support this in Foundation we will continue to see 3rd party 
>>> libraries that do this.
>> 
>> The proposal's been out for less than 24 hours, is it really productive to 
>> already be taking our ball and go home over such a minor thing?
> 
> I don’t think that’s what I’m doing at all.  This is a fantastic proposal.  
> I’m still working through it and writing up my more detailed thoughts.
> 
> That said, as with many (most?) first drafts, there is room for improvement.  
> I think it’s worth pointing out the syntax that many of us would like to use 
> for decoding and at least considering including it in the proposal.  If the 
> answer is that it’s trivial for those who want to use subscripts to write the 
> wrappers for return type inference and / or subscripts themselves that’s ok.  
> But it’s a fair topic for discussion and should at least be addressed as an 
> alternative that was rejected for a specific reason.
> 
>> 
>> Zach Waldowski
>> z...@waldowski.me 
>> 
>> 
>> 
>> 
>> ___
>> swift-evolution mailing list
>> swift-evolution@swift.org 
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution 
> 

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Itai Ferber via swift-evolution

Thanks for the comments, David.
I responded to #2 in a separate email, but wanted to get back to 
responding to #1.


In implementing this, I have had the same thoughts. Ideally, one day, we 
would be able to migrate the implementation of this away from the 
compiler to public API (through reflection, property behaviors, or 
similar). If the compiler offers external features that would allow us 
to do everything that we want, I would be more than happy to move the 
implementation from inside the compiler to outside of it.


On 16 Mar 2017, at 0:09, David Hart wrote:


First of all, great proposal :D

Brent, earlier in the thread makes a lot of good points. But I’d 
still like to discuss two subjects:


1) What makes the proposal really stand on its feet compared to 
third-party libraries is the compiler generation magic. I feel divided 
about it. On one hand, this is the only solution today to have this 
level of type and key safety. But on another hand, I have the 
impression that future versions of Swift (with more reflection, 
property behaviours, lenses, etc…) would dramatically affect how 
this subject is treated and implemented. Are you worried that we are 
asking the compiler to do work which might be un-necessary in the 
future? That this topic would be better expressed with more powerful 
language features? Any plans to migrate for this API to smoothly 
migrate to those features in the future?


2) Libraries like Marshal (https://github.com/utahiosmac/Marshal 
) and Unbox 
(https://github.com/JohnSundell/Unbox 
) don’t require the decoding 
functions to provide the type: those functions are generic on the 
return turn and it’s automatically inferred:


func decode(key: Key) -> T

self.stringProperty = decode(key: .stringProperty) // correct 
specialisation of the generic function chosen by the compiler


Is there a reason the proposal did not choose this solution? Its quite 
sweet.



Swift Archival & Serialization
Proposal: SE- 
Author(s): Itai Ferber , Michael LeHew 
, Tony Parker 

Review Manager: TBD
Status: Awaiting review
Associated PRs:
#8124 
#8125 



___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Itai Ferber via swift-evolution
Subscripts, by the way, would not help here, since they cannot throw. 
`decode` must be able to throw.
[SR-238](https://bugs.swift.org/browse/SR-238?jql=text%20~%20%22subscript%20throw%22); 
for Apple folks, 28775436.


On 16 Mar 2017, at 11:46, Matthew Johnson via swift-evolution wrote:

> On Mar 16, 2017, at 1:34 PM, Zach Waldowski via swift-evolution 
 wrote:


On Thu, Mar 16, 2017, at 02:23 PM, Matthew Johnson via 
swift-evolution wrote:
I don’t have an example but I don’t see a problem either.  There 
are two options for specifying the return type manually.  We can use 
the signature you used above and use `as` to specify the expected 
type:


let i = decode(.myKey) as Int


The awkwardness of this syntax is exactly what I'm referring to. 
Would a beginner know to use "as Int" or ": Int"? Why would they? The 
"prettiness" of the simple case doesn't make up for how difficult it 
is to understand and fix its failure cases.


Any official Swift or Foundation API shouldn't, or shouldn't need to, 
make use of "tricky" syntax.


I don’t think this is especially tricky.  Nevertheless, we can avoid 
requiring this syntax by moving the type argument to the end and 
providing a default.  But I think return type inference is worth 
supporting.  It has become widely adopted by the community already in 
this use case.




If we don’t support this in Foundation we will continue to see 3rd 
party libraries that do this.


The proposal's been out for less than 24 hours, is it really 
productive to already be taking our ball and go home over such a 
minor thing?


I don’t think that’s what I’m doing at all.  This is a fantastic 
proposal.  I’m still working through it and writing up my more 
detailed thoughts.


That said, as with many (most?) first drafts, there is room for 
improvement.  I think it’s worth pointing out the syntax that many 
of us would like to use for decoding and at least considering 
including it in the proposal.  If the answer is that it’s trivial 
for those who want to use subscripts to write the wrappers for return 
type inference and / or subscripts themselves that’s ok.  But it’s 
a fair topic for discussion and should at least be addressed as an 
alternative that was rejected for a specific reason.




Zach Waldowski
z...@waldowski.me 




___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution




___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread David Hart via swift-evolution

> On 16 Mar 2017, at 19:34, Zach Waldowski via swift-evolution 
>  wrote:
> 
> On Thu, Mar 16, 2017, at 02:23 PM, Matthew Johnson via swift-evolution wrote:
>> I don’t have an example but I don’t see a problem either.  There are two 
>> options for specifying the return type manually.  We can use the signature 
>> you used above and use `as` to specify the expected type:
>> 
>> let i = decode(.myKey) as Int
> 
> The awkwardness of this syntax is exactly what I'm referring to. Would a 
> beginner know to use "as Int" or ": Int"? Why would they? The "prettiness" of 
> the simple case doesn't make up for how difficult it is to understand and fix 
> its failure cases.
> 
> Any official Swift or Foundation API shouldn't, or shouldn't need to, make 
> use of "tricky" syntax.

Two arguments:

1) Most of the time, you will be setting the return value of decode into a 
typed property and will not need ‘as’.
2) Even when you do need it, its not tricky syntax: it’s the official way to 
direct the type inference engine in Swift.

David.

>> If we don’t support this in Foundation we will continue to see 3rd party 
>> libraries that do this.
> 
> The proposal's been out for less than 24 hours, is it really productive to 
> already be taking our ball and go home over such a minor thing?
> 
> Zach Waldowski
> z...@waldowski.me 
> 
> 
> 
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Itai Ferber via swift-evolution
I’m going to reply to this thread as a whole — apologies if 
there’s someone’s comment that I’ve missed.


This is something that has come up in internal review, and we’ve 
certainly given it thought. As Zach has already mentioned, the primary 
concern with overloading based on return type is ambiguity.
There are many cases in which Swift’s type system currently does not 
handle ambiguity in the way that you would expect, and it can be very 
surprising. For instance,


```swift
func foo() -> Int { return 42 }
func foo() -> Double { return .pi }
func consumesInt(_ x : Int) { print(x) }

let x = foo() // Ambiguous use of foo()
consumesInt(x) // Even though x is going to be used as an Int
let y: Int = x // Same here
```

`let x = foo() as Int` works now, but it actually didn’t always — 
until a somewhat recent version of Swift AFAICT, the only way to resolve 
the ambiguity was through `let x: Int = foo()`. This has since been 
fixed, but it was very confusing to try to figure out the unambiguous 
way to call it.


Keep in mind that this isn’t an unreasonable thing to want to do:

```swift
struct Foo {
var x: Int
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

// Want to process an element before it’s assigned.
let x = container.decode(forKey: .x) // Ambiguous call

// Or whatever.
if x < 0 {
self.x = x + 100
else {
self.x = x * 200
}
}
}
```

You can write `let x: Int = container.decode(…)` or `let x = 
container.decode(…) as Int`, but this isn’t always intuitive.
Consider also that the metatype would also be necessary for 
`decode(_ type: Value.Type, forKey: Key) -> Value` 
because the return value of that certainly could be ambiguous in many 
cases.


Finally, the metatype arg allows you to express the following 
succinctly: `let v: SuperClass = container.decode(SubClass.self, forKey: 
.v)`.


In the general case (`decode`) we would need the 
metatype to avoid ambiguity. It’s not strictly necessary for primitive 
types, but helps in the case of ambiguity, and solves the conceptual 
overhead of "Why do I specify the type sometimes but not others? Why are 
some of these types special? Should I always provide the type? Why 
wouldn’t I?"


Matthew offered `func decode(_ key: Key, as type: T.Type = T.self) 
throws -> T` which looks appealing, but:


1. Doesn’t help resolve the ambiguity either
2. Allows for 3 ways of expressing the same thing (`let x: Int = 
decode(key)`, `let x = decode(key) as Int`, and `let x = decode(key, as: 
Int.self)`)


The cognitive overhead of figuring out all of the ambiguity goes away 
when we’re consistent everywhere.
FWIW, too, I am not convinced that Foundation should add API just 
because 3rd parties will add it. The ambiguity in the general case 
cannot be solved by wrappers, and I would prefer to provide one simple, 
consistent solution; if 3rd parties would like to add wrappers for their 
own sake, then I certainly encourage that.


On 16 Mar 2017, at 11:46, Matthew Johnson via swift-evolution wrote:

> On Mar 16, 2017, at 1:34 PM, Zach Waldowski via swift-evolution 
 wrote:


On Thu, Mar 16, 2017, at 02:23 PM, Matthew Johnson via 
swift-evolution wrote:
I don’t have an example but I don’t see a problem either.  There 
are two options for specifying the return type manually.  We can use 
the signature you used above and use `as` to specify the expected 
type:


let i = decode(.myKey) as Int


The awkwardness of this syntax is exactly what I'm referring to. 
Would a beginner know to use "as Int" or ": Int"? Why would they? The 
"prettiness" of the simple case doesn't make up for how difficult it 
is to understand and fix its failure cases.


Any official Swift or Foundation API shouldn't, or shouldn't need to, 
make use of "tricky" syntax.


I don’t think this is especially tricky.  Nevertheless, we can avoid 
requiring this syntax by moving the type argument to the end and 
providing a default.  But I think return type inference is worth 
supporting.  It has become widely adopted by the community already in 
this use case.




If we don’t support this in Foundation we will continue to see 3rd 
party libraries that do this.


The proposal's been out for less than 24 hours, is it really 
productive to already be taking our ball and go home over such a 
minor thing?


I don’t think that’s what I’m doing at all.  This is a fantastic 
proposal.  I’m still working through it and writing up my more 
detailed thoughts.


That said, as with many (most?) first drafts, there is room for 
improvement.  I think it’s worth pointing out the syntax that many 
of us would like to use for decoding and at least considering 
including it in the proposal.  If the answer is that it’s trivial 
for those who want to use subscripts to write the wrappers for return 
type inference and / or subscripts themselves that’s ok.  But 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Itai Ferber via swift-evolution

Thanks for the thorough and detailed review, Brent! Responses inline.

On 15 Mar 2017, at 21:19, Brent Royal-Gordon wrote:

On Mar 15, 2017, at 3:40 PM, Itai Ferber via swift-evolution 
 wrote:


Hi everyone,

The following introduces a new Swift-focused archival and 
serialization API as part of the Foundation framework. We’re 
interested in improving the experience and safety of performing 
archival and serialization, and are happy to receive community 
feedback on this work.


Thanks to all of the people who've worked on this. It's a great 
proposal.



Specifically:

	• It aims to provide a solution for the archival of Swift struct 
and enum types


I see a lot of discussion here of structs and classes, and an example 
of an enum without associated values, but I don't see any discussion 
of enums with associated values. Can you sketch how you see people 
encoding such types?


For example, I assume that `Optional` is going to get some special 
treatment, but if it doesn't, how would you write its `encode(to:)` 
method?
`Optional` values are accepted and vended directly through the API. The 
`encode(_:forKey:)` methods take optional values directly, and 
`decodeIfPresent(_:forKey:)` vend optional values.


`Optional` is special in this way — it’s a primitive part of the 
system. It’s actually not possible to write an `encode(to:)` method 
for `Optional`, since the representation of null values is up to the 
encoder and the format it’s working in; `JSONEncoder`, for instance, 
decides on the representation of `nil` (JSON `null`). It wouldn’t be 
possible to ask `nil` to encode itself in a reasonable way.


What about a more complex enum, like the standard library's 
`UnicodeDecodingResult`:


enum UnicodeDecodingResult {
case emptyInput
case error
case scalarValue(UnicodeScalar)
}

Or, say, an `Error`-conforming type from one of my projects:

public enum SQLError: Error {
case connectionFailed(underlying: Error)
case executionFailed(underlying: Error, statement: SQLStatement)
case noRecordsFound(statement: SQLStatement)
case extraRecordsFound(statement: SQLStatement)
	case columnInvalid(underlying: Error, key: ColumnSpecifier, 
statement: SQLStatement)
	case valueInvalid(underlying: Error, key: AnySQLColumnKey, 
statement: SQLStatement)

}

(You can assume that all the types in the associated values are 
`Codable`.)
Sure — these cases specifically do not derive `Codable` conformance 
because the specific representation to choose is up to you. Two possible 
ways to write this, though there are many others (I’m simplifying 
these cases here a bit, but you can extrapolate this):


```swift
// Approach 1
// This produces either {"type": 0} for `.noValue`, or {"type": 1, 
"value": …} for `.associated`.

public enum EnumWithAssociatedValue : Codable {
case noValue
case associated(Int)

private enum CodingKeys : CodingKey {
case type
case value
}

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let type = try container.decode(Int.self, forKey: .type)
switch type {
case 0:
self = .noValue
case 1:
let value = try container.decode(Int.self, forKey: .value)
self = .associated(value)
default:
throw …
}
}

public func encode(to encoder: Encoder) throws {
let container = encoder.container(keyedBy: codingKeys.self)
switch self {
case .noValue:
try container.encode(0, forKey: .type)
case .associated(let value):
try container.encode(1, forKey: .type)
try container.encode(value, forKey: .value)
}
}
}

// Approach 2
// Produces `0`, `1`, or `2` for `.noValue1`, `.noValue2`, and 
`.noValue3` respectively.
// Produces {"type": 3, "value": …} and {"type": 4, "value": …} for 
`.associated1` and `.associated2`.

public enum EnumWithAssociatedValue : Codable {
case noValue1
case noValue2
case noValue3
case associated1(Int)
case associated2(String)

private enum CodingKeys : CodingKey {
case type
case value
}

public init(from decoder: Decoder) throws {
if let container = try? decoder.singleValueContainer() {}
let type = container.decode(Int.self)
switch type {
case 0: self = .noValue1
case 1: self = .noValue2
case 2: self = .noValue3
default: throw …
}
} else {
let container = try decoder.container(keyedBy: 
CodingKeys.self)

let type = container.decode(Int.self, forKey: .type)
switch type {
case 3:
let value = container.decode(Int.self, forKey: .value)
self = 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Matthew Johnson via swift-evolution

> On Mar 16, 2017, at 1:34 PM, Zach Waldowski via swift-evolution 
>  wrote:
> 
> On Thu, Mar 16, 2017, at 02:23 PM, Matthew Johnson via swift-evolution wrote:
>> I don’t have an example but I don’t see a problem either.  There are two 
>> options for specifying the return type manually.  We can use the signature 
>> you used above and use `as` to specify the expected type:
>> 
>> let i = decode(.myKey) as Int
> 
> The awkwardness of this syntax is exactly what I'm referring to. Would a 
> beginner know to use "as Int" or ": Int"? Why would they? The "prettiness" of 
> the simple case doesn't make up for how difficult it is to understand and fix 
> its failure cases.
> 
> Any official Swift or Foundation API shouldn't, or shouldn't need to, make 
> use of "tricky" syntax.

I don’t think this is especially tricky.  Nevertheless, we can avoid requiring 
this syntax by moving the type argument to the end and providing a default.  
But I think return type inference is worth supporting.  It has become widely 
adopted by the community already in this use case.

> 
>> If we don’t support this in Foundation we will continue to see 3rd party 
>> libraries that do this.
> 
> The proposal's been out for less than 24 hours, is it really productive to 
> already be taking our ball and go home over such a minor thing?

I don’t think that’s what I’m doing at all.  This is a fantastic proposal.  I’m 
still working through it and writing up my more detailed thoughts.

That said, as with many (most?) first drafts, there is room for improvement.  I 
think it’s worth pointing out the syntax that many of us would like to use for 
decoding and at least considering including it in the proposal.  If the answer 
is that it’s trivial for those who want to use subscripts to write the wrappers 
for return type inference and / or subscripts themselves that’s ok.  But it’s a 
fair topic for discussion and should at least be addressed as an alternative 
that was rejected for a specific reason.

> 
> Zach Waldowski
> z...@waldowski.me 
> 
> 
> 
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Zach Waldowski via swift-evolution
On Thu, Mar 16, 2017, at 02:23 PM, Matthew Johnson via swift-evolution wrote:
> I don’t have an example but I don’t see a problem either.  There are
> two options for specifying the return type manually.  We can use the
> signature you used above and use `as` to specify the expected type:
> 

> let i = decode(.myKey) as Int



The awkwardness of this syntax is exactly what I'm referring to. Would a
beginner know to use "as Int" or ": Int"? Why would they? The
"prettiness" of the simple case doesn't make up for how difficult it is
to understand and fix its failure cases.


Any official Swift or Foundation API shouldn't, or shouldn't need to,
make use of "tricky" syntax.


> If we don’t support this in Foundation we will continue to see 3rd
> party libraries that do this.


The proposal's been out for less than 24 hours, is it really productive
to already be taking our ball and go home over such a minor thing?


Zach Waldowski

z...@waldowski.me








___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Matthew Johnson via swift-evolution

> On Mar 16, 2017, at 1:06 PM, David Hart via swift-evolution 
>  wrote:
> 
> 
> On 16 Mar 2017, at 16:53, Zach Waldowski  > wrote:
> 
>>> On Mar 16, 2017, at 3:09 AM, David Hart via swift-evolution 
>>> > wrote:
>>> 
>>> 2) Libraries like Marshal (https://github.com/utahiosmac/Marshal 
>>> ) and Unbox 
>>> (https://github.com/JohnSundell/Unbox 
>>> ) don’t require the decoding 
>>> functions to provide the type: those functions are generic on the return 
>>> turn and it’s automatically inferred:
>>> 
>>> func decode(key: Key) -> T
>>> 
>>> self.stringProperty = decode(key: .stringProperty) // correct 
>>> specialisation of the generic function chosen by the compiler
>>> 
>>> Is there a reason the proposal did not choose this solution? Its quite 
>>> sweet.
>> 
>> IMHO those are only “sweet” until you need to decode a value out to 
>> something other than a typed value, then it’s ambiguity city.
> 
> Other than a typed value? Can you give an example?

I don’t have an example but I don’t see a problem either.  There are two 
options for specifying the return type manually.  We can use the signature you 
used above and use `as` to specify the expected type:

let i = decode(.myKey) as Int

We can also use the type argument but provide a default value:

func decode(_ key: Key, as type: T.Type = T.self) throws -> T

let i = decode(key: .myKey, as: Int.self)

I think the Foundation team should strongly consider one of these signatures 
and allow us to rely on return type inference when desired.  If this isn’t 
provided by Foundation we’ll see a bunch of wrappers that do this.  Why not 
include it in the standard interface?  

The same argument can be made for providing a subscript instead of or in 
addition to `decode`.  Of course exposing a proper subscript interface isn’t 
possible until we have throwing subscripts.  Decoding is one of the major 
motivating use cases for throwing subscripts.  With Foundation tackling this 
topic in Swift 4 maybe it would be good to consider bringing throwing 
subscripts in scope and using them in the interface to KeyedDecodingContainer.  

Subscript with return type inference is the natural interface for a keyed 
decoder (obviously IMO).  If we don’t support this in Foundation we will 
continue to see 3rd party libraries that do this.  I think it would be better 
to provide the same interface and implementation to everyone directly in 
Foundation itself.

> 
>> There are many ways to solve that, but none of them are conducive to 
>> beginners. Using the metatype to seed the generic resolution is the only 
>> thing I’d get behind, personally.
>> 
>> Zach Waldowski
>> z...@waldowski.me 
>> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread David Hart via swift-evolution

> On 16 Mar 2017, at 16:53, Zach Waldowski  wrote:
> 
>> On Mar 16, 2017, at 3:09 AM, David Hart via swift-evolution 
>>  wrote:
>> 
>> 2) Libraries like Marshal (https://github.com/utahiosmac/Marshal) and Unbox 
>> (https://github.com/JohnSundell/Unbox) don’t require the decoding functions 
>> to provide the type: those functions are generic on the return turn and it’s 
>> automatically inferred:
>> 
>> func decode(key: Key) -> T
>> 
>> self.stringProperty = decode(key: .stringProperty) // correct specialisation 
>> of the generic function chosen by the compiler
>> 
>> Is there a reason the proposal did not choose this solution? Its quite sweet.
> 
> IMHO those are only “sweet” until you need to decode a value out to something 
> other than a typed value, then it’s ambiguity city.

Other than a typed value? Can you give an example?

> There are many ways to solve that, but none of them are conducive to 
> beginners. Using the metatype to seed the generic resolution is the only 
> thing I’d get behind, personally.
> 
> Zach Waldowski
> z...@waldowski.me
> 
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Joe Groff via swift-evolution

> On Mar 16, 2017, at 10:21 AM, Itai Ferber  wrote:
> 
> On 15 Mar 2017, at 19:12, Joe Groff wrote:
> 
> 
> On Mar 15, 2017, at 6:46 PM, Itai Ferber  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 { ... }, 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(_ type: Key.Type) -> Cont 
> where Cont.Key == Key {
> // return something
> }
> 
> This looks promising so far — let's try to make it concrete:
> 
> struct ConcreteContainer : Container {
> typealias Key = K
> }
> 
> func container(_ type: Key.Type) -> Cont 
> where Cont.Key == Key {
> return ConcreteContainer() // error: Cannot convert return expression of 
> type 'ConcreteContainer' 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() 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.

-Joe
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Itai Ferber via swift-evolution



On 15 Mar 2017, at 19:12, Joe Groff wrote:


On Mar 15, 2017, at 6:46 PM, Itai Ferber  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 { ... }, 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(_ type: Key.Type) 
-> Cont where Cont.Key == Key {

// return something
}

This looks promising so far — let's try to make it concrete:

struct ConcreteContainer : Container {
typealias Key = K
}

func container(_ type: Key.Type) 
-> Cont where Cont.Key == Key {
return ConcreteContainer() // error: Cannot convert return 
expression of type 'ConcreteContainer' 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() 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).
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Zach Waldowski via swift-evolution
> On Mar 16, 2017, at 3:09 AM, David Hart via swift-evolution 
>  wrote:
> 
> 2) Libraries like Marshal (https://github.com/utahiosmac/Marshal 
> ) and Unbox 
> (https://github.com/JohnSundell/Unbox ) 
> don’t require the decoding functions to provide the type: those functions are 
> generic on the return turn and it’s automatically inferred:
> 
> func decode(key: Key) -> T
> 
> self.stringProperty = decode(key: .stringProperty) // correct specialisation 
> of the generic function chosen by the compiler
> 
> Is there a reason the proposal did not choose this solution? Its quite sweet.

IMHO those are only “sweet” until you need to decode a value out to something 
other than a typed value, then it’s ambiguity city. There are many ways to 
solve that, but none of them are conducive to beginners. Using the metatype to 
seed the generic resolution is the only thing I’d get behind, personally.

Zach Waldowski
z...@waldowski.me

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Vincent Esche via swift-evolution
On Thu, Mar 16, 2017 at 1:45 AM, Zach Waldowski via swift-evolution <
swift-evolution@swift.org> wrote:

> Holy cow. There's much to digest here (so much so that my initial
> response, which quoted its content, was denied by the mailing list). After
> an initial reading, I don't just want this now, I want it yesterday. I'm
> already imaging the encoder/decoders I want to build. Very exciting.
>

+1 on this (having skimmed through it briefly)!
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread David Hart via swift-evolution
First of all, great proposal :D

Brent, earlier in the thread makes a lot of good points. But I’d still like to 
discuss two subjects:

1) What makes the proposal really stand on its feet compared to third-party 
libraries is the compiler generation magic. I feel divided about it. On one 
hand, this is the only solution today to have this level of type and key 
safety. But on another hand, I have the impression that future versions of 
Swift (with more reflection, property behaviours, lenses, etc…) would 
dramatically affect how this subject is treated and implemented. Are you 
worried that we are asking the compiler to do work which might be un-necessary 
in the future? That this topic would be better expressed with more powerful 
language features? Any plans to migrate for this API to smoothly migrate to 
those features in the future?

2) Libraries like Marshal (https://github.com/utahiosmac/Marshal 
) and Unbox 
(https://github.com/JohnSundell/Unbox ) 
don’t require the decoding functions to provide the type: those functions are 
generic on the return turn and it’s automatically inferred:

func decode(key: Key) -> T

self.stringProperty = decode(key: .stringProperty) // correct specialisation of 
the generic function chosen by the compiler

Is there a reason the proposal did not choose this solution? Its quite sweet.

> Swift Archival & Serialization
> Proposal: SE- 
> Author(s): Itai Ferber , Michael LeHew 
> , Tony Parker 
> Review Manager: TBD
> Status: Awaiting review
> Associated PRs:
> #8124 
> #8125 ___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Goffredo Marocchi via swift-evolution


Sent from my iPhone

> On 16 Mar 2017, at 01:18, Joe Groff via swift-evolution 
>  wrote:
> 
> Congrats on getting this out! A question from the field:
> 
> https://twitter.com/mdiep/status/842178457115230210 Why does the Swift 
> Serialization API proposal use abstract base classes?
> 

Hopefully because we realise we need abstract classes as a feature ;)? 

> -Joe
> 
> 
>> On Mar 15, 2017, at 3:40 PM, Itai Ferber via swift-evolution 
>>  wrote:
>> 
>> Hi everyone,
>> 
>> The following introduces a new Swift-focused archival and serialization API 
>> as part of the Foundation framework. We’re interested in improving the 
>> experience and safety of performing archival and serialization, and are 
>> happy to receive community feedback on this work.
>> Because of the length of this proposal, the Appendix and Alternatives 
>> Considered sections have been omitted here, but are available in the full 
>> proposal on the swift-evolution repo. The full proposal also includes an 
>> Unabridged API for further consideration.
>> 
>> Without further ado, inlined below.
>> 
>> — Itai
>> 
>> Swift Archival & Serialization
>>• Proposal: SE-
>>• Author(s): Itai Ferber, Michael LeHew, Tony Parker
>>• Review Manager: TBD
>>• Status: Awaiting review
>>• Associated PRs:
>>• #8124
>>• #8125
>> Introduction
>> Foundation's current archival and serialization APIs (NSCoding, 
>> NSJSONSerialization, NSPropertyListSerialization, etc.), while fitting for 
>> the dynamism of Objective-C, do not always map optimally into Swift. This 
>> document lays out the design of an updated API that improves the developer 
>> experience of performing archival and serialization in Swift.
>> 
>> Specifically:
>> 
>>• It aims to provide a solution for the archival of Swift struct and enum 
>> types
>>• It aims to provide a more type-safe solution for serializing to 
>> external formats, such as JSON and plist
>> Motivation
>> The primary motivation for this proposal is the inclusion of native Swift 
>> enum and struct types in archival and serialization. Currently, developers 
>> targeting Swift cannot participate in NSCoding without being willing to 
>> abandon enum and structtypes — NSCoding is an @objc protocol, conformance to 
>> which excludes non-class types. This is can be limiting in Swift because 
>> small enums and structs can be an idiomatic approach to model 
>> representation; developers who wish to perform archival have to either forgo 
>> the Swift niceties that constructs like enumsprovide, or provide an 
>> additional compatibility layer between their "real" types and their 
>> archivable types.
>> 
>> Secondarily, we would like to refine Foundation's existing serialization 
>> APIs (NSJSONSerialization and NSPropertyListSerialization) to better match 
>> Swift's strong type safety. From experience, we find that the conversion 
>> from the unstructured, untyped data of these formats into strongly-typed 
>> data structures is a good fit for archival mechanisms, rather than taking 
>> the less safe approach that 3rd-party JSON conversion approaches have taken 
>> (described further in an appendix below).
>> 
>> We would like to offer a solution to these problems without sacrificing ease 
>> of use or type safety.
>> 
>> Agenda
>> This proposal is the first stage of three that introduce different facets of 
>> a whole Swift archival and serialization API:
>> 
>>• This proposal describes the basis for this API, focusing on the 
>> protocols that users adopt and interface with
>>• The next stage will propose specific API for new encoders
>>• The final stage will discuss how this new API will interop with 
>> NSCoding as it is today
>> SE- provides stages 2 and 3.
>> 
>> Proposed solution
>> We will be introducing the following new types:
>> 
>>• protocol Codable: Adopted by types to opt into archival. Conformance 
>> may be automatically derived in cases where all properties are also Codable.
>>• protocol CodingKey: Adopted by types used as keys for keyed containers, 
>> replacing String keys with semantic types. Conformance may be automatically 
>> derived in most cases.
>>• protocol Encoder: Adopted by types which can take Codable values and 
>> encode them into a native format.
>>• class KeyedEncodingContainer: Subclasses of this 
>> type provide a concrete way to store encoded values by CodingKey. Types 
>> adopting Encoder should provide subclasses of KeyedEncodingContainer to vend.
>>• protocol SingleValueEncodingContainer: Adopted by types which 
>> provide a concrete way to store a single encoded value. Types adopting 
>> Encoder should provide types conforming to SingleValueEncodingContainer to 
>> vend (but in many cases will be able to conform to it themselves).
>>• protocol Decoder: Adopted by types which can take payloads in a native 
>> format and decode Codable values 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-16 Thread Brent Royal-Gordon via swift-evolution
> On Mar 15, 2017, at 9:19 PM, Brent Royal-Gordon  
> wrote:
> 
> I think we'd be better off having `encode(_:forKey:)` not take an optional; 
> instead, we should have `Optional` conform to `Codable` and behave in some 
> appropriate way. Exactly how to implement it might be a little tricky because 
> of nested optionals; I suppose a `none` would have to measure how many levels 
> of optionality there are between it and a concrete value, and then encode 
> that information into the data. I think our `NSNull` bridging is doing 
> something broadly similar right now.
> 
> I know that this is not the design you would use in Objective-C, but Swift 
> uses `Optional` differently from how Objective-C uses `nil`. Swift APIs 
> consider `nil` and absent to be different things; where they can both occur, 
> good Swift APIs use doubled-up Optionals to be precise about the situation. I 
> think the design needs to be a little different to accommodate that.

Re-reading this after sending it, I realized I should probably be a lot more 
concrete about what I envision here.

Basically, what I think is:

* There should be primitives for `encode(_ value: NSNull)` and `decode(_ type: 
NSNull.Type)`. Yes, even though it's a singleton. In JSON, this should 
emit/read a `null`; in plist format, I suppose it will simply have to interpret 
absence of the corresponding key as `null`, because there's nothing better we 
can do there.

* An `Optional.some(x)` should encode as an `x` would.

* An `Optional.none`, where `Wrapped` is not itself an `Optional`, should 
encode as an `NSNull`.

* An `Optional.none`, where `Wrapped` *is* itself an `Optional`, should encode 
as one of the Swift runtime's magic optional sentinel objects.

That will do the best job we can manage of correctly representing nested 
optionals.

-- 
Brent Royal-Gordon
Architechies

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-15 Thread Zach Waldowski via swift-evolution
Another issue of scale - I had to switch to a native mail client as replying 
inline severely broke my webmail client. ;-)

Again, lots of love here. Responses inline.

> On Mar 15, 2017, at 6:40 PM, Itai Ferber via swift-evolution 
>  wrote:
> Proposed solution
> We will be introducing the following new types:
> 
> protocol Codable: Adopted by types to opt into archival. Conformance may be 
> automatically derived in cases where all properties are also Codable.
FWIW I think this is acceptable compromise. If the happy path is derived 
conformances, only-decodable or only-encodable types feel like a lazy way out 
on the part of a user of the API, and builds a barrier to proper testing.
> [snip]
> 
> Structured types (i.e. types which encode as a collection of properties) 
> encode and decode their properties in a keyed manner. Keys may be 
> String-convertible or Int-convertible (or both), and user types which have 
> properties should declare semantic key enums which map keys to their 
> properties. Keys must conform to the CodingKey protocol:
> public protocol CodingKey { <##snip##> }

A few things here:

The protocol leaves open the possibility of having both a String or Int 
representation, or neither. What should a coder do in either case? Are the 
representations intended to be mutually exclusive, or not? The protocol design 
doesn’t seem particularly matching with the flavor of Swift; I’d expect 
something along the lines of a CodingKey enum and the protocol 
CodingKeyRepresentable. It’s also possible that the concerns of the two are 
orthogonal enough that they deserve separate container(keyedBy:) requirements.

Speaking of the mutually exclusive representations - what above serializations 
that doesn’t code as one of those two things? YAML can have anything be a 
“key”, and despite that being not particularly sane, it is a use case.
> For most types, String-convertible keys are a reasonable default; for 
> performance, however, Int-convertible keys are preferred, and Encoders may 
> choose to make use of Ints over Strings. Framework types should provide keys 
> which have both for flexibility and performance across different types of 
> Encoders. It is generally an error to provide a key which has neither a 
> stringValue nor an intValue.
> 

Could you speak a little more to using Int-convertible keys for performance? I 
get the feeling int-based keys parallel the legacy of NSCoder’s older design, 
and I don’t really see anyone these days supporting non-keyed archivers. They 
strike me as fragile. What other use cases are envisioned for ordered archiving 
than that?
> [snip]
> 
> Keyed Encoding Containers
> 
> Keyed encoding containers are the primary interface that most Codable types 
> interact with for encoding and decoding. Through these, Codable types have 
> strongly-keyed access to encoded data by using keys that are semantically 
> correct for the operations they want to express.
> 
> Since semantically incompatible keys will rarely (if ever) share the same key 
> type, it is impossible to mix up key types within the same container (as is 
> possible with Stringkeys), and since the type is known statically, keys get 
> autocompletion by the compiler.
> 
> open class KeyedEncodingContainer {

Like others, I’m a little bummed about this part of the design. Your reasoning 
up-thread is sound, but I chafe a bit on having to reabstract and a little more 
on having to be a reference type. Particularly knowing that it’s got a bit more 
overhead involved… I /like/ that NSKeyedArchiver can simply push some state and 
pass itself as the next encoding container down the stack.

> open func encode(_ value: Value?, forKey key: Key) throws

Does this win anything over taking a Codable?

> open func encode(_ value: Bool?,   forKey key: Key) throws
> open func encode(_ value: Int?,forKey key: Key) throws
> open func encode(_ value: Int8?,   forKey key: Key) throws
> open func encode(_ value: Int16?,  forKey key: Key) throws
> open func encode(_ value: Int32?,  forKey key: Key) throws
> open func encode(_ value: Int64?,  forKey key: Key) throws
> open func encode(_ value: UInt?,   forKey key: Key) throws
> open func encode(_ value: UInt8?,  forKey key: Key) throws
> open func encode(_ value: UInt16?, forKey key: Key) throws
> open func encode(_ value: UInt32?, forKey key: Key) throws
> open func encode(_ value: UInt64?, forKey key: Key) throws
> open func encode(_ value: Float?,  forKey key: Key) throws
> open func encode(_ value: Double?, forKey key: Key) throws
> open func encode(_ value: String?, forKey key: Key) throws
> open func encode(_ value: Data?,   forKey key: Key) throws

What is the motivation behind abandoning the idea of “primitives” from the 
Alternatives Considered? Performance? Being unable to close the protocol?

What ways is encoding a value envisioned to fail? I understand wanting to allow 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-15 Thread Brent Royal-Gordon via swift-evolution
> On Mar 15, 2017, at 3:40 PM, Itai Ferber via swift-evolution 
>  wrote:
> 
> Hi everyone,
> 
> The following introduces a new Swift-focused archival and serialization API 
> as part of the Foundation framework. We’re interested in improving the 
> experience and safety of performing archival and serialization, and are happy 
> to receive community feedback on this work.

Thanks to all of the people who've worked on this. It's a great proposal.

> Specifically:
> 
>   • It aims to provide a solution for the archival of Swift struct and 
> enum types

I see a lot of discussion here of structs and classes, and an example of an 
enum without associated values, but I don't see any discussion of enums with 
associated values. Can you sketch how you see people encoding such types?

For example, I assume that `Optional` is going to get some special treatment, 
but if it doesn't, how would you write its `encode(to:)` method?

What about a more complex enum, like the standard library's 
`UnicodeDecodingResult`:

enum UnicodeDecodingResult {
case emptyInput
case error
case scalarValue(UnicodeScalar)
}

Or, say, an `Error`-conforming type from one of my projects:

public enum SQLError: Error {
case connectionFailed(underlying: Error)
case executionFailed(underlying: Error, statement: SQLStatement)
case noRecordsFound(statement: SQLStatement)
case extraRecordsFound(statement: SQLStatement)
case columnInvalid(underlying: Error, key: ColumnSpecifier, 
statement: SQLStatement)
case valueInvalid(underlying: Error, key: AnySQLColumnKey, 
statement: SQLStatement)
}

(You can assume that all the types in the associated values are `Codable`.)

I don't necessarily assume that the compiler should write conformances to these 
sorts of complicated enums for me (though that would be nice!); I'm just 
wondering what the designers of this feature envision people doing in cases 
like these.

>   • protocol Codable: Adopted by types to opt into archival. Conformance 
> may be automatically derived in cases where all properties are also Codable.

Have you given any consideration to supporting types which only need to decode? 
That seems likely to be common when interacting with web services.

>   • protocol CodingKey: Adopted by types used as keys for keyed 
> containers, replacing String keys with semantic types. Conformance may be 
> automatically derived in most cases.
>   • protocol Encoder: Adopted by types which can take Codable values and 
> encode them into a native format.
>   • class KeyedEncodingContainer: Subclasses of 
> this type provide a concrete way to store encoded values by CodingKey. Types 
> adopting Encoder should provide subclasses of KeyedEncodingContainer to vend.
>   • protocol SingleValueEncodingContainer: Adopted by types which 
> provide a concrete way to store a single encoded value. Types adopting 
> Encoder should provide types conforming to SingleValueEncodingContainer to 
> vend (but in many cases will be able to conform to it themselves).
>   • protocol Decoder: Adopted by types which can take payloads in a 
> native format and decode Codable values out of them.
>   • class KeyedDecodingContainer: Subclasses of 
> this type provide a concrete way to retrieve encoded values from storage by 
> CodingKey. Types adopting Decoder should provide subclasses of 
> KeyedDecodingContainer to vend.
>   • protocol SingleValueDecodingContainer: Adopted by types which 
> provide a concrete way to retrieve a single encoded value from storage. Types 
> adopting Decoder should provide types conforming to 
> SingleValueDecodingContainer to vend (but in many cases will be able to 
> conform to it themselves).

I do want to note that, at this point in the proposal, I was sort of thinking 
you'd gone off the deep end modeling this. Having read the whole thing, I now 
understand what all of these things do, but this really is a very large 
subsystem. I think it's worth asking if some of these types can be eliminated 
or combined.

> Structured types (i.e. types which encode as a collection of properties) 
> encode and decode their properties in a keyed manner. Keys may be 
> String-convertible or Int-convertible (or both),

What does "may" mean here? That, at runtime, the encoder will test for the 
preferred key type and fall back to the other one? That seems a little bit 
problematic.

I'm also quite worried about how `Int`-convertible keys will interact with code 
synthesis. The obvious way to assign integers—declaration order—would mean that 
reordering declarations would invisibly break archiving, potentially (if the 
types were compatible) without breaking anything in an error-causing way even 
at runtime. You could sort the names, but then adding a new property would 

Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-15 Thread Joe Groff via swift-evolution

> On Mar 15, 2017, at 6:46 PM, Itai Ferber  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 { ... }, 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(_ type: Key.Type) -> Cont 
> where Cont.Key == Key {
> // return something
> }
> 
> This looks promising so far — let's try to make it concrete:
> 
> struct ConcreteContainer : Container {
> typealias Key = K
> }
> 
> func container(_ type: Key.Type) -> Cont 
> where Cont.Key == Key {
> return ConcreteContainer() // error: Cannot convert return 
> expression of type 'ConcreteContainer' 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() 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
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Foundation Swift Archival & Serialization

2017-03-15 Thread Itai Ferber via swift-evolution

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 { ... }`, which 
is the "ideal" version of what we're trying to represent

* Let's try this with a protocol first (simplified here):

  ```swift
  protocol Container {
associatedtype Key : CodingKey
  }

  func container(_ type: Key.Type) 
-> Cont where Cont.Key == Key {

// return something
  }
  ```

  This looks promising so far — let's try to make it concrete:

  ```swift
  struct ConcreteContainer : Container {
typealias Key = K
  }

  func container(_ type: Key.Type) 
-> Cont where Cont.Key == Key {
return ConcreteContainer() // error: Cannot convert return 
expression of type 'ConcreteContainer' 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:

  ```swift
  func container... {
return ConcreteContainer() as! Cont
  }
  ```

  This compiles fine! Hmm, let's try to use it:

  ```swift
  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.


On 15 Mar 2017, at 18:18, Joe Groff wrote:


Congrats on getting this out! A question from the field:

https://twitter.com/mdiep/status/842178457115230210 Why does the Swift 
Serialization API proposal use abstract base classes?


-Joe


On Mar 15, 2017, at 3:40 PM, Itai Ferber via swift-evolution 
 wrote:


Hi everyone,

The following introduces a new Swift-focused archival and 
serialization API as part of the Foundation framework. We’re 
interested in improving the experience and safety of performing 
archival and serialization, and are happy to receive community 
feedback on this work.
Because of the length of this proposal, the Appendix and Alternatives 
Considered sections have been omitted here, but are available in the 
full proposal on the swift-evolution repo. The full proposal also 
includes an Unabridged API for further consideration.


Without further ado, inlined below.

— Itai

Swift Archival & Serialization
• Proposal: SE-
• Author(s): Itai Ferber, Michael LeHew, Tony Parker
• Review Manager: TBD
• Status: Awaiting review
• Associated PRs:
• #8124
• #8125
Introduction
Foundation's current archival and serialization APIs (NSCoding, 
NSJSONSerialization, NSPropertyListSerialization, etc.), while 
fitting for the dynamism of Objective-C, do not always map optimally 
into Swift. This document lays out the design of an updated API that 
improves the developer experience of performing archival and 
serialization in Swift.


Specifically:

	• It aims to provide a solution for the archival of Swift struct 
and enum types
	• It aims to provide a more type-safe solution for serializing to 
external formats, such as JSON and plist

Motivation
The primary motivation for this proposal is the inclusion of native 
Swift enum and struct types in archival and serialization. Currently, 
developers targeting Swift cannot participate in NSCoding without 
being willing to abandon enum and structtypes — NSCoding is an 
@objc protocol, conformance to which excludes non-class types. This 
is can be limiting in Swift because small enums and structs can be an 
idiomatic approach to model representation; developers who wish to 
perform archival have to either forgo the Swift niceties that 
constructs like enumsprovide, or provide an additional compatibility 
layer between their "real" types and their archivable types.


Secondarily, 

  1   2   >