Re: [swift-users] Refining generics in classes

2017-11-16 Thread Itai Ferber via swift-users

Hi Jon,

To clarify for those wondering, this is happening because the 
`doAThing()` method dispatches statically to `doSomething()` based on 
`NetworkRequests`’s `T`; since `doAThing()` isn’t overridden in 
`CompressedNetworkRequest`, the method is inherited directly, including 
that static dispatch.

To pull this example out a bit:

```swift
protocol X {}
protocol Y : X {}

class Foo {
var value: T

init(value: T) {
self.value = value
}

func doSomething() {
doThing(value)
}
}

class Bar : Foo {}

func doThing(_ v: T) { print("doThing()") }
func doThing(_ v: T) { print("doThing()") }

extension Int : Y {}
Foo(value: 42).doSomething() // doThing
Bar(value: 42).doSomething() // doThing
```

In order to not inherit that static dispatch, `doSomething` needs to be 
overridden in `Bar`, even if to call the same function:


```swift
// …

class Bar : Foo {
override func doSomething() {
doThing(value) // statically dispatches based on T : Y
}
}

// …

Foo(value: 42).doSomething() // doThing()
Bar(value: 42).doSomething() // doThing()
```

Unfortunately, I don’t think there’s a great way around this, short 
of duplicating the calls which do that sort of dispatch.
If you can somehow funnel some of these calls through one call site, it 
might make your life a bit easier.


— Itai

On 15 Nov 2017, at 20:42, Jon Shier via swift-users wrote:


Swift Users:
	I have a generics use case which has somewhat stumped me. I have two 
related protocols, JSONDecodable and CompressedDecodable, and 
CompressedDecodable inherits from JSONDecodable (though that 
relationship isn’t strictly necessary). I also have a generic 
function that’s overloaded for each of those protocols. I’m trying 
to write a class to make a network request expecting a generic 
response type of either JSONDecodable or CompressedDecodable. However, 
it doesn’t seem possible to write it in such a way that the overload 
I need is called. Instead, it’s always the superclass’ type’s 
overload that is called. For example:


protocol JSONDecodable { init() }
protocol CompressedDecodable: JSONDecodable { }

class NetworkRequest {

var response: T?

func doAThing() {
response = doSomething()
}
}

class CompressedNetworkRequest: 
NetworkRequest {


}

func doSomething() -> T {
print("One: \(T.self)")
return T()
}

func doSomething() -> T {
print("Two: \(T.self)")
return T()
}

struct Uno: JSONDecodable { }
struct Dos: CompressedDecodable { }

NetworkRequest().doAThing()
CompressedNetworkRequest().doAThing()

In a playground this prints:

One: Uno
One: Dos

Ultimately, I understand why this happens (NetworkRequest’s generic 
type is always going to be JSONDecodable, no matter if it’s actually 
a subtype). Is there any way, aside from completely duplicating the 
class, to call the overload appropriate for the type passed in a class 
like this?




Jon Shier
___
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users
___
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


Re: [swift-users] Parsing Decimal values from JSON

2017-10-31 Thread Itai Ferber via swift-users
I can’t speak to any resistance you’ve seen from the Swift team (nor 
to any performance issues you’ve encountered with 
`JSONSerialization`), but just keep in mind that

a) `JSONSerialization` is maintained by the Foundation team, and
b) maintaining a separate JSON parsing implementation just for Swift is 
a great way to introduce new, separate, likely incompatible bugs


That being said, we’ve considered it, and continue to consider it — 
there is just a cost-benefit analysis that goes into prioritizing 
developer time.


On 31 Oct 2017, at 10:18, Jon Shier wrote:

The appropriate solution here would be for Swift to have its own 
native JSON parser that allows direct decoding into generic types 
without the intermediary of JSONSerialization. For whatever reason 
there seems to be resistance to this from the Swift team, but until we 
have that ability, these types of issues will keep coming up, and the 
performance overhead of JSONSerialization with JSONDecoder on top of 
it will continue to leave Swift without a very performant JSON 
solution.

That said, I appreciate the support given Codable on this list.



Jon

On Oct 31, 2017, at 1:07 PM, Itai Ferber via swift-users 
<swift-users@swift.org> wrote:


Hi Evtim,

Just want to give some context for this.
This is due to the fact that JSONEncoder and JSONDecoder are 
currently based on JSONSerialization: when you go to decode some JSON 
data, the data is deserialized using JSONSerialization, and then 
decoded into your types by JSONDecoder. At the JSONSerialization 
level, however, there is no way to know whether a given numeric value 
is meant to be interpreted as a Double or as a Decimal.


There are subtle differences to decoding as either, so there is no 
behavior that could satisfy all use cases. JSONSerialization has to 
make a decision, so if the number could fit losslessly in a Double, 
it will prefer that to a Decimal. This allows guaranteed precise 
round-tripping of all Double values at the cost of different behavior 
when decoding a Decimal.


In practice, this might not really matter in the end based on how you 
use the number (e.g. the loss in precision can be so minute as to be 
insignificant) — what is your use case here? And can you give some 
numeric values for which this is problematic for you?


As others have mentioned, one way to guarantee decoding a numeric 
string in a specific way is to actually encode it and decode it as a 
String, then convert into a Decimal where you need it, e.g.


import Foundation

struct Foo : Codable {
var number: Decimal

public init(number: Decimal) {
self.number = number
}

private enum CodingKeys : String, CodingKey {
case number
}

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: 
CodingKeys.self)
let stringValue = try container.decode(String.self, forKey: 
.number)

guard let decimal = Decimal(string: stringValue) else {
throw DecodingError.dataCorruptedError(forKey: .number, 
in: container, debugDescription: "Invalid numeric value.")

}

self.number = decimal
}

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.number.description, forKey: 
.number)

}
}


let foo = Foo(number: Decimal(string: 
"2.71828182845904523536028747135266249775")!)
print(foo) // => Foo(number: 
2.71828182845904523536028747135266249775)


let encoder = JSONEncoder()
let data = try encoder.encode(foo)
print(String(data: data, encoding: .utf8)!) // => 
{"number":"2.71828182845904523536028747135266249775"}


let decoder = JSONDecoder()
let decoded = try decoder.decode(Foo.self, from: data)
print(decoded) // => Foo(number: 
2.71828182845904523536028747135266249775)


print(decoded.number == foo.number) // => true
— Itai

On 28 Oct 2017, at 11:23, Evtim Papushev via swift-users wrote:

Hello :)

I am trying to find a way to parse a number as Decimal without losing 
the number's precision.


It seems that the JSON decoder parses it as Double then converts it 
to Decimal which introduces errors in the parsing. That behavior is 
in fact incorrect.


Does anyone know if there is a way to obtain the raw data for this 
specific field so I can write the conversion code?


Thanks,
Evtim

___
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users 
<https://lists.swift.org/mailman/listinfo/swift-users>

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



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


Re: [swift-users] Parsing Decimal values from JSON

2017-10-31 Thread Itai Ferber via swift-users

Hi Evtim,

Just want to give some context for this.
This is due to the fact that `JSONEncoder` and `JSONDecoder` are 
currently based on `JSONSerialization`: when you go to decode some JSON 
data, the data is deserialized using `JSONSerialization`, and then 
decoded into your types by `JSONDecoder`. At the `JSONSerialization` 
level, however, there is no way to know whether a given numeric value is 
meant to be interpreted as a `Double` or as a `Decimal`.


There are subtle differences to decoding as either, so there is no 
behavior that could satisfy all use cases. `JSONSerialization` has to 
make a decision, so if the number could fit losslessly in a `Double`, it 
will prefer that to a `Decimal`. This allows guaranteed precise 
round-tripping of all `Double` values at the cost of different behavior 
when decoding a `Decimal`.


In practice, this might not really matter in the end based on how you 
use the number (e.g. the loss in precision can be so minute as to be 
insignificant) — what is your use case here? And can you give some 
numeric values for which this is problematic for you?


As others have mentioned, one way to guarantee decoding a numeric string 
in a specific way is to actually encode it and decode it as a `String`, 
then convert into a `Decimal` where you need it, e.g.


```swift
import Foundation

struct Foo : Codable {
var number: Decimal

public init(number: Decimal) {
self.number = number
}

private enum CodingKeys : String, CodingKey {
case number
}

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let stringValue = try container.decode(String.self, forKey: 
.number)

guard let decimal = Decimal(string: stringValue) else {
throw DecodingError.dataCorruptedError(forKey: .number, in: 
container, debugDescription: "Invalid numeric value.")

}

self.number = decimal
}

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.number.description, forKey: .number)
}
}


let foo = Foo(number: Decimal(string: 
"2.71828182845904523536028747135266249775")!)

print(foo) // => Foo(number: 2.71828182845904523536028747135266249775)

let encoder = JSONEncoder()
let data = try encoder.encode(foo)
print(String(data: data, encoding: .utf8)!) // => 
{"number":"2.71828182845904523536028747135266249775"}


let decoder = JSONDecoder()
let decoded = try decoder.decode(Foo.self, from: data)
print(decoded) // => Foo(number: 
2.71828182845904523536028747135266249775)


print(decoded.number == foo.number) // => true
```

— Itai

On 28 Oct 2017, at 11:23, Evtim Papushev via swift-users wrote:


Hello :)

I am trying to find a way to parse a number as Decimal without losing 
the number's precision.


It seems that the JSON decoder parses it as Double then converts it to 
Decimal which introduces errors in the parsing. That behavior is in 
fact incorrect.


Does anyone know if there is a way to obtain the raw data for this 
specific field so I can write the conversion code?


Thanks,
Evtim

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


Re: [swift-users] Array not Encodable - error at runtime, not compile time?

2017-10-26 Thread Itai Ferber via swift-users

Hi Robert,

When the conditional conformance feature arrives in Swift, it will allow 
us to express `extension Array : Encodable where Element : Encodable` 
and `extension Array : Decodable where Element : Decodable`.
At the moment, this isn’t possible, so `Array` is unconditionally 
`Codable` and the failure happens at runtime. This will be a 
compile-time error in a future version of Swift.


— Itai

On 26 Oct 2017, at 9:47, Robert Nikander via swift-users wrote:


Hi,

This error makes perfect sense, but I’m surprised it's a runtime 
error. I expected it at compile time. Am I doing something wrong? Is 
this on the type system to-do list?


  let c = JSONEncoder()
  struct Foo { … }
  let fs: [Foo] = [ Foo(...) ]
  let data = try! c.encode(fs)   // Didn’t think this would compile

The runtime error is: fatal error: Array does not conform to 
Encodable because Foo does not conform to Encodable.


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


Re: [swift-users] dealing with heterogenous lists/dictionary with Codable

2017-10-19 Thread Itai Ferber via swift-users
Right now, collection types in the standard library (`Array`, 
`Dictionary`, and `Set`) employ a workaround for the lack of conditional 
conformance, which would allow us to expose things like `extension Array 
: Codable where Element : Codable` (i.e. `Array` is `Codable` if and 
only if `T` is `Codable`).
These collections unconditionally conform to `Codable` and trap at 
runtime if the type is not actually `Codable`. The synthesis complaint 
is an explicit check in the compiler so we don’t go ahead and happily 
synthesize code on your behalf that would just trap at runtime.


When the conditional conformance feature lands, `[String : Any]() is 
Codable` should return `false`.


On 19 Oct 2017, at 14:15, Kevin Nattinger wrote:

So, what I see as the problem here is contradictory compiler 
statements:


MyPlayground.playground:5:9: note: cannot automatically synthesize 
'Encodable' because '[String : Any]' does not conform to 'Encodable'

let someDict: [String : Any]
^

warning: MyPlayground.playground:8:18: warning: 'is' test is always 
true

[String : Any]() is Codable
 ^

So is it codable or isn't it? You can use a [String: Any] in encode() 
and decode() directly, so why doesn't it get compiler support? At the 
least, the message needs to be updated to something that's actually 
true.


On Oct 19, 2017, at 1:38 PM, David Sweeris via swift-users 
 wrote:


Oh! Yeah, my bad... You are correct; I'd started thinking like I was 
on -evolution instead of -users.



On Oct 19, 2017, at 1:29 PM, Itai Ferber > wrote:


Mm, the point I’m trying to get at here is that JSON is inherently 
untyped while Swift is strongly typed, and the two don’t line up.
It doesn’t really make sense to ask to decode an existential 
because there’s not enough type information to influence what you 
get back.


On 19 Oct 2017, at 13:20, David Sweeris wrote:

I think if you can figure that out, you’re halfway to letting 
protocols conform to themselves.


(Syntactically, I would probably say that something like 
“Codable.Self” would read well, but I think that already means 
something. Maybe the answer will become clearer when we rework the 
reflection APIs?)


Sent from my iPhone

On Oct 19, 2017, at 13:13, Itai Ferber > wrote:


Even then, that wouldn’t necessarily help in the general case. If 
you decode {"key" : 1} as [String : Codable], what concrete type 
would 1 have? Int? Double? Int8? (Arguments can be made for any one 
of these, but the key here is that it is inherently ambiguous and 
there isn’t necessarily a good answer.)


On 19 Oct 2017, at 12:57, David Sweeris wrote:

On Oct 19, 2017, at 12:50 PM, David Baraff via swift-users 
> wrote:


Yes; this is a case where anywhere in the code base I want to just 
say

struct MyNewType : Codable {
// add codable datatypes
}

and don’t want/can’t always go to the centralized place to add 
it in.
Is there some extension-like trick I can pull off that lets me 
spread the implementation out over different files/libraries?


Ah, ok.

No, I don't think you'll be able to do that until/unless Swift gets 
more macro/metaprogramming features. Maybe if protocols ever get to 
conform to themselves? That's a common request, but implementing it 
is apparently beyond tricky. I'm pretty sure somebody's working on 
it, but "bigger fish" and all that...


- Dave Sweeris





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



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


Re: [swift-users] dealing with heterogenous lists/dictionary with Codable

2017-10-19 Thread Itai Ferber via swift-users
Mm, the point I’m trying to get at here is that JSON is inherently 
untyped while Swift is strongly typed, and the two don’t line up.
It doesn’t really make sense to ask to decode an existential because 
there’s not enough type information to influence what you get back.


On 19 Oct 2017, at 13:20, David Sweeris wrote:

I think if you can figure that out, you’re halfway to letting 
protocols conform to themselves.


(Syntactically, I would probably say that something like 
“Codable.Self” would read well, but I think that already means 
something. Maybe the answer will become clearer when we rework the 
reflection APIs?)


Sent from my iPhone


On Oct 19, 2017, at 13:13, Itai Ferber  wrote:

Even then, that wouldn’t necessarily help in the general case. If 
you decode {"key" : 1} as [String : Codable], what concrete type 
would 1 have? Int? Double? Int8? (Arguments can be made for any one 
of these, but the key here is that it is inherently ambiguous and 
there isn’t necessarily a good answer.)


On 19 Oct 2017, at 12:57, David Sweeris wrote:

On Oct 19, 2017, at 12:50 PM, David Baraff via swift-users 
 wrote:


Yes; this is a case where anywhere in the code base I want to just 
say

struct MyNewType : Codable {
// add codable datatypes
}

and don’t want/can’t always go to the centralized place to add it 
in.
Is there some extension-like trick I can pull off that lets me spread 
the implementation out over different files/libraries?


Ah, ok.

No, I don't think you'll be able to do that until/unless Swift gets 
more macro/metaprogramming features. Maybe if protocols ever get to 
conform to themselves? That's a common request, but implementing it 
is apparently beyond tricky. I'm pretty sure somebody's working on 
it, but "bigger fish" and all that...


- Dave Sweeris




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


Re: [swift-users] dealing with heterogenous lists/dictionary with Codable

2017-10-19 Thread Itai Ferber via swift-users
Even then, that wouldn’t necessarily help in the general case. If you 
decode `{"key" : 1}` as `[String : Codable]`, what concrete type would 
`1` have? `Int`? `Double`? `Int8`? (Arguments can be made for any one of 
these, but the key here is that it is inherently ambiguous and there 
isn’t necessarily a good answer.)


On 19 Oct 2017, at 12:57, David Sweeris wrote:

On Oct 19, 2017, at 12:50 PM, David Baraff via swift-users 
 wrote:


Yes; this is a case where anywhere in the code base I want to just 
say

struct MyNewType : Codable {
// add codable datatypes
}

and don’t want/can’t always go to the centralized place to add it 
in.
Is there some extension-like trick I can pull off that lets me spread 
the implementation out over different files/libraries?


Ah, ok.

No, I don't think you'll be able to do that until/unless Swift gets 
more macro/metaprogramming features. Maybe if protocols ever get to 
conform to themselves? That's a common request, but implementing it is 
apparently beyond tricky. I'm pretty sure somebody's working on it, 
but "bigger fish" and all that...


- Dave Sweeris
___
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


Re: [swift-users] dealing with heterogenous lists/dictionary with Codable

2017-10-19 Thread Itai Ferber via swift-users
Then no, this wouldn’t be possible unless you could somehow express 
something like:


```swift
// Cribbing some C++-style syntax here
enum OneOf : Codable where T… : Codable {
cases t…(T…)
}
```

where someone would be able to express to you that they want to store a 
`OneOf` through your enum, or something like 
that.


You could do that in a non-extensible way with something like

```swift
enum MyEnum : Codable /* where T : Codable */ /* <- when conditional 
conformance arrives */ {

case int(Int)
case string(String)
case custom(T)
case list([MyEnum])
case dictionary([String : MyEnum])
}
```

but that’s not truly heterogeneous without extending with more generic 
types.


If you don’t know the type you need to decode, then you won’t be 
able to do this unless the encoder/decoder supports somehow mapping the 
type to and from data in the payload.


On 19 Oct 2017, at 12:52, David Baraff wrote:

An even bigger “no can’t do that”: the enum would be in some 
base/low-level library, and thus can’t know about new types that 
exist in higher-up libraries.
___
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


Re: [swift-users] dealing with heterogenous lists/dictionary with Codable

2017-10-19 Thread Itai Ferber via swift-users

David,

Is there an issue with extending the enum as necessary with new cases to 
support what you need?


```swift
enum MyType : Codable {
case int(Int)
case string(String)
case newThingy(NewThingy)
case list([MyType])
case dictionary([String : MyType])

// …
}
```

`NewThingy` can still be declared on its own and have a synthesized 
`Codable` implementation.


— Itai

On 19 Oct 2017, at 12:14, David Baraff wrote:

My apologies.  I misstated the problem: I don’t want to just limit 
to Int, String, [Int], etc. but also allow structures where


struct NewThingy : Codable {
let data1: T1
let data2: T2
}

where T1 and T2 are themselves Codable.

So basically, back to wanting to let the compiler do the work, when I 
make new structures, while still allowing for heterogenous containers.






Begin forwarded message:


From: Itai Ferber 
Subject: Re: [swift-users] dealing with heterogenous lists/dictionary 
with Codable

Date: October 19, 2017 at 10:40:28 AM PDT
To: David Baraff 
Cc: Geordie Jay , swift-users 



Why are you stuck? I think the following matches your needs, no?

import Foundation

enum MyType : Codable, Equatable {
case int(Int)
case string(String)
case list([MyType])
case dictionary([String : MyType])

public init(from decoder: Decoder) throws {
// Can be made prettier, but as a simple example:
let container = try decoder.singleValueContainer()
do {
self = .int(try container.decode(Int.self))
} catch DecodingError.typeMismatch {
do {
self = .string(try container.decode(String.self))
} catch DecodingError.typeMismatch {
do {
self = .list(try container.decode([MyType].self))
} catch DecodingError.typeMismatch {
self = .dictionary(try container.decode([String : 
MyType].self))

}
}
}
}

public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .int(let int): try container.encode(int)
case .string(let string): try container.encode(string)
case .list(let list): try container.encode(list)
case .dictionary(let dictionary): try 
container.encode(dictionary)

}
}

static func ==(_ lhs: MyType, _ rhs: MyType) -> Bool {
switch (lhs, rhs) {
case (.int(let int1), .int(let int2)): return int1 == int2
case (.string(let string1), .string(let string2)): return 
string1 == string2
case (.list(let list1), .list(let list2)): return list1 == 
list2
case (.dictionary(let dict1), .dictionary(let dict2)): return 
dict1 == dict2

default: return false
}
}
}

let values: MyType = .list([.int(42), .string("hello!"), 
.list([.int(9), .string("hi")]), .dictionary(["zero": .int(0), "one": 
.int(1)])])

print(values)

let encoder = JSONEncoder()
let data = try encoder.encode(values)
print(String(data: data, encoding: .utf8)!) // => 
[42,"hello!",[9,"hi"],{"zero":0,"one":1}]


let decoder = JSONDecoder()
let decoded = try decoder.decode(MyType.self, from: data)
print(decoded)

print(values == decoded) // => true
On 19 Oct 2017, at 20:15, David Baraff wrote:

Begin forwarded message:


From: Itai Ferber >
Subject: Re: [swift-users] dealing with heterogenous 
lists/dictionary with Codable

Date: October 19, 2017 at 9:39:25 AM PDT
To: David Baraff >
Cc: Geordie Jay >, 
swift-users >


Hi David and Geordie,

That approach won’t work — encoders and decoders only work 
directly with concrete Codable types (e.g. String, Int, MyFoo [where 
MyFoo is Codable], etc.).
This is by design: since there is no type information stored in the 
JSON payload, there isn’t necessarily a way to tell how to decode 
the type you’re looking at, so asking for a generalCodable` 
isn’t helpful.


Since it’s unlikely that what you truly need is a [String : Any] 
but really a [String : ], one easy 
way to decode this type is to create a wrapper enum or similar which 
overrides init(from:) to be able to decode from one of those types. 
You can then ask to decode a [String : MyWrapperType] and use that 
instead.


What types are you expecting in the dictionary?




The problem is that I want to be able to encode types T where
(a) T is String, Int
(b) lists of T
(c ) dictionaries of type 

The problem is the recursive nature: yes, my types are simple (say 
only base types String and Int) but the “nesting” level may be 
quite deep (a list of list of dictionaries of 

Re: [swift-users] dealing with heterogenous lists/dictionary with Codable

2017-10-19 Thread Itai Ferber via swift-users

Hi Geordie,

Yep, that’s the difference here — you can’t decode something with 
an existential type; it has to be concrete (like you’re doing).
The reason for this is that it’s simply not possible to determine what 
type to decode just from the structure of the payload.


Consider the following:

```swift
let json = """
{"name": "Itai", "email": "ifer...@apple.com"}
""".data(using: .utf8)!

let thing = try decoder.decode(Codable.self, from: json)
```

What should the type of `thing` be? Is it `[String : String]` because 
that’s what’s in the JSON?

What if I expected it to be `Person`, which is defined as

```swift
struct Person : Codable {
let name: String
let email: String
}
```

There’s no difference whether the `Codable` thing is at the top level 
or in a dictionary — if I try to decode `[String : Codable]`, I would 
run into the same issue.
The type needs to be concrete so we can figure out what initializer to 
call; if you write your own type (like an `enum`, which is what is 
almost always appropriate in this case), you can supply that type as the 
concrete type to attempt.


— Itai

On 19 Oct 2017, at 12:38, Geordie Jay wrote:

David Baraff  schrieb am Do. 19. Okt. 2017 um 
21:35:





Begin forwarded message:

From: Geordie Jay 

Subject: Re: [swift-users] dealing with heterogenous lists/dictionary 
with

Codable

Date: October 19, 2017 at 12:24:44 PM PDT

To: David Baraff , Itai Ferber 



Cc: swift-users 




David Baraff  schrieb am Do. 19. Okt. 2017 um
21:14:

My apologies.  I misstated the problem: I don’t want to just limit 
to

Int, String, [Int], etc. but also allow structures where

struct NewThingy : Codable {
let data1: T1
let data2: T2
}

where T1 and T2 are themselves Codable.



This is already possible, just not with dictionaries of unknown types
(because they’re not known to be Codable)


Sure, but I don’t want to give a dictionary of unknown types: i’m 
very

happy to say that my dictionary is
[String : Codable]

but
struct Foo : Codable {
let d: [String : Codable]
}

doesn’t work; the d inside F is not itself Codable.



That’s strange. We’re actually doing exactly this and it works for 
us

(although we are using a concrete Codable type rather than the Codable
metatype itself).

Maybe it’s worth filing a bug on Jira

Good luck.





So basically, back to wanting to let the compiler do the work, when 
I
make new structures, while still allowing for heterogenous 
containers.




It’s also possible to give the compiler hints as to what decodes 
into

what. Have you looked at the docs on the Apple foundation page?


https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types

Geordie









Begin forwarded message:

From: Itai Ferber 

Subject: Re: [swift-users] dealing with heterogenous 
lists/dictionary

with Codable

Date: October 19, 2017 at 10:40:28 AM PDT

To: David Baraff 

Cc: Geordie Jay , swift-users 




Why are you stuck? I think the following matches your needs, no?

import Foundation
enum MyType : Codable, Equatable {
case int(Int)
case string(String)
case list([MyType])
case dictionary([String : MyType])

public init(from decoder: Decoder) throws {
// Can be made prettier, but as a simple example:
let container = try decoder.singleValueContainer()
do {
self = .int(try container.decode(Int.self))
} catch DecodingError.typeMismatch {
do {
self = .string(try container.decode(String.self))
} catch DecodingError.typeMismatch {
do {
self = .list(try 
container.decode([MyType].self))

} catch DecodingError.typeMismatch {
self = .dictionary(try container.decode([String 
: MyType].self))

}
}
}
}

public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .int(let int): try container.encode(int)
case .string(let string): try container.encode(string)
case .list(let list): try container.encode(list)
case .dictionary(let dictionary): try 
container.encode(dictionary)

}
}

static func ==(_ lhs: MyType, _ rhs: MyType) -> Bool {
switch (lhs, rhs) {
case (.int(let int1), .int(let int2)): return int1 == int2
case (.string(let string1), .string(let string2)): return 
string1 == string2
case (.list(let list1), .list(let list2)): return list1 == 
list2
case (.dictionary(let dict1), .dictionary(let dict2)): 
return dict1 == dict2

default: return false
}
}
}
let values: MyType = .list([.int(42), .string("hello!"), 

Re: [swift-users] dealing with heterogenous lists/dictionary with Codable

2017-10-19 Thread Itai Ferber via swift-users

Why are you stuck? I think the following matches your needs, no?

```swift
import Foundation

enum MyType : Codable, Equatable {
case int(Int)
case string(String)
case list([MyType])
case dictionary([String : MyType])

public init(from decoder: Decoder) throws {
// Can be made prettier, but as a simple example:
let container = try decoder.singleValueContainer()
do {
self = .int(try container.decode(Int.self))
} catch DecodingError.typeMismatch {
do {
self = .string(try container.decode(String.self))
} catch DecodingError.typeMismatch {
do {
self = .list(try container.decode([MyType].self))
} catch DecodingError.typeMismatch {
self = .dictionary(try container.decode([String : 
MyType].self))

}
}
}
}

public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .int(let int): try container.encode(int)
case .string(let string): try container.encode(string)
case .list(let list): try container.encode(list)
case .dictionary(let dictionary): try 
container.encode(dictionary)

}
}

static func ==(_ lhs: MyType, _ rhs: MyType) -> Bool {
switch (lhs, rhs) {
case (.int(let int1), .int(let int2)): return int1 == int2
case (.string(let string1), .string(let string2)): return 
string1 == string2
case (.list(let list1), .list(let list2)): return list1 == 
list2
case (.dictionary(let dict1), .dictionary(let dict2)): return 
dict1 == dict2

default: return false
}
}
}

let values: MyType = .list([.int(42), .string("hello!"), .list([.int(9), 
.string("hi")]), .dictionary(["zero": .int(0), "one": .int(1)])])

print(values)

let encoder = JSONEncoder()
let data = try encoder.encode(values)
print(String(data: data, encoding: .utf8)!) // => 
[42,"hello!",[9,"hi"],{"zero":0,"one":1}]


let decoder = JSONDecoder()
let decoded = try decoder.decode(MyType.self, from: data)
print(decoded)

print(values == decoded) // => true
```

On 19 Oct 2017, at 20:15, David Baraff wrote:


Begin forwarded message:


From: Itai Ferber 
Subject: Re: [swift-users] dealing with heterogenous lists/dictionary 
with Codable

Date: October 19, 2017 at 9:39:25 AM PDT
To: David Baraff 
Cc: Geordie Jay , swift-users 



Hi David and Geordie,

That approach won’t work — encoders and decoders only work 
directly with concrete Codable types (e.g. String, Int, MyFoo [where 
MyFoo is Codable], etc.).
This is by design: since there is no type information stored in the 
JSON payload, there isn’t necessarily a way to tell how to decode 
the type you’re looking at, so asking for a generalCodable` isn’t 
helpful.


Since it’s unlikely that what you truly need is a [String : Any] 
but really a [String : ], one easy 
way to decode this type is to create a wrapper enum or similar which 
overrides init(from:) to be able to decode from one of those types. 
You can then ask to decode a [String : MyWrapperType] and use that 
instead.


What types are you expecting in the dictionary?




The problem is that I want to be able to encode types T where
(a) T is String, Int
(b) lists of T
(c ) dictionaries of type 

The problem is the recursive nature: yes, my types are simple (say 
only base types String and Int) but the “nesting” level may be 
quite deep (a list of list of dictionaries of > wrote:



I mean can you do something along the lines of

let codableDict = stringAnyDict as? [String : Codable]

?

I’m not at a computer to test it myself




David Baraff > 
schrieb am Do. 19. Okt. 2017 um 15:45:
That’s exactly what I want.  The ironic part is that I got my 
dictionary by decoding a Json file.  If that’s where my dictionary 
came from, is there a simple way of coercing the Json serialization 
routines to give me back codables, rather than Anys?



Sent from my iPad

On Oct 19, 2017, at 3:38 AM, Geordie Jay > 

Re: [swift-users] dealing with heterogenous lists/dictionary with Codable

2017-10-19 Thread Itai Ferber via swift-users

Hi David and Geordie,

That approach won’t work — encoders and decoders only work directly 
with concrete `Codable` types (e.g. `String`, `Int`, `MyFoo` [where 
`MyFoo` is `Codable], etc.).
This is by design: since there is no type information stored in the JSON 
payload, there isn’t necessarily a way to tell how to decode the type 
you’re looking at, so asking for a general `Codable` isn’t helpful.


Since it’s unlikely that what you truly need is a `[String : Any]` but 
really a `[String : ]`, one easy way to 
decode this type is to create a wrapper `enum` or similar which 
overrides `init(from:)` to be able to decode from one of those types. 
You can then ask to decode a `[String : MyWrapperType]` and use that 
instead.


What types are you expecting in the dictionary?

— Itai

On 19 Oct 2017, at 18:11, David Baraff via swift-users wrote:

I’ll try.  Is that cast smart enough to apply recursively? We shall 
see.


Sent from my iPad


On Oct 19, 2017, at 7:34 AM, Geordie Jay  wrote:

I mean can you do something along the lines of

let codableDict = stringAnyDict as? [String : Codable]

?

I’m not at a computer to test it myself




David Baraff  schrieb am Do. 19. Okt. 2017 um 
15:45:
That’s exactly what I want.  The ironic part is that I got my 
dictionary by decoding a Json file.  If that’s where my dictionary 
came from, is there a simple way of coercing the Json serialization 
routines to give me back codables, rather than Anys?



Sent from my iPad


On Oct 19, 2017, at 3:38 AM, Geordie Jay  wrote:


David Baraff via swift-users  schrieb am Do. 
19. Okt. 2017 um 03:47:

So I have simple structs like this:

struct Library: Codable {
let domain: String
let unit: String
}

and it’s super-simple to serialize.  Yay.

But:

struct LibraryGroup : Codable { // I wish...
   let libraries: [Library]
   let someDict: [String : Any]
}


I haven’t tried this, but is it possible to have a dictionary of 
[String : Codable] ? Because that’s exactly the type requirements 
you’re describing, no?


Geordie



So what I’m looking for is something where if the values in 
someDict are themselves Codable, I can serialize things, and if 
they’re not, I can’t.  In my previous scheme, I was using 
NSKeyedArchiver to serialize everything, manualy, including 
someDict; in trying to switch to Codable I ran smack into the fact 
that Codable wants to know what all the types are, in advance.


Am I just stuck?  How do I get the best of both worlds, where the 
compiler can make use of the fact that it can see the data types 
of my structures, while still being able to serialize heterogenous 
data like is found in LibraryGroup?


Is my only alternative to write a custom coder for LibraryGroup?  
Is there any hope I could teach Codable what to do with

[String: Any]

?


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




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


Re: [swift-users] No Generic Decoders?

2017-09-05 Thread Itai Ferber via swift-users

Hi Jon,

This was a conscious choice in the API design, for three main reasons:

1. There is a big difference between the API surface exposed at the 
top-level for encoding and decoding and the middle levels. A method like 
`decode(_ type: T, from data: Data)` is really only appropriate at the 
top level of a given decoder, and likewise, exposing individual encoding 
and decoding containers is really only appropriate at the middle levels. 
We intentionally left these APIs separate to avoid exposing methods in 
inappropriate places (so the `Decoder` protocol doesn’t expose the 
top-level method)
2. Among top-level interfaces, there is variability in what different 
decoders can expose. `JSONDecoder`, for instance, exposes only a 
`decode(_ type: T, from data: Data)` method, while `PropertyListDecoder` 
has another method which also exposes the 
`PropertyListSerialization.PropertyListFormat` of the decoded data, 
which would not be appropriate to expose on `JSONDecoder`. In the 
future, these two might diverge further if we decide to specify the API 
even further, but more importantly, other decoders might find a 
different top-level API to be more appropriate than these methods (e.g. 
a format which only allows top-level dictionaries might want to expose 
only a decode method which accepts a dictionary type)
3. Given that, we found that it would be too confusing to expose 
top-level encoders and decoders as a separate type from 
`Encoder`/`Decoder` for not much benefit


If you find the concept useful for your own work and are willing to 
sacrifice some portability, you can always define a protocol with the 
interface appropriate for your project and have these decoders conform 
to that protocol.


— Itai

On 2 Sep 2017, at 18:47, Jon Shier via swift-users wrote:


Swift Users:
	I’ve been exploring the creation of Decodable response serializers 
for Alamofire. However, there doesn’t actually seem to be any way to 
express the notion of a generic decoder. The Decoder protocol itself 
doesn’t require a `decode(type:from:)` method, and neither 
JSONDecoder or PropertyListDecoder conform to Decoder in the first 
place. Were these facts conscious choices or oversights? It certainly 
seems very useful to be able to treat decoders generically.




Jon Shier
___
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users
___
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


Re: [swift-users] Swift 4 emulating Decoder behaviour

2017-07-14 Thread Itai Ferber via swift-users

Hi Joanna,

Your example doesn’t work for a few reasons:

1. You’re getting a compiler error because of the difference between 
the representation of metatypes (`Foo.Type` for some type `Foo`) of 
concrete types (e.g. `String`, `Int`), and protocols (e.g. 
`DefaultValueProvider`). Some of the compiler folks can correct my exact 
use of terminology here, but the essence is this: when you `as?`-cast a 
type to a concrete type (e.g. `type as? String.self`), you’ll get a 
concrete metatype which can be used dynamically as you would a concrete 
type elsewhere. When you `as?`-cast a type to a protocol type (`type as? 
DefaultValueProvider`), however, you get a protocol-constrained metatype 
which is not concrete and cannot be used dynamically as you would 
statically. You can call statically-known protocol methods on the 
metatype (e.g. `(type as! DefaultValueProvider).init()`), but the 
concrete type is not known. You can see this with a small example:


  ```swift
  protocol P {
  init()
  }

  extension Int : P {}

  let type: Any.Type = Int.self
  if let specific = type as? P.Type {
  // type of specific.init() is P, not Int
  print(specific.init())
  }
  ```

  This, then coincides with:

2. The fact that methods generic on types can only take concrete type 
parameters. Protocol metatypes cannot be passed in as you would a 
concrete metatype:


  ```swift
  protocol P {}
  extension Int : P {}

  func foo(_ type: T.Type) {
  print(type)
  }

  let type: Any.Type = Int.self
  foo(type) // cannot invoke 'foo' with an argument list of type 
'(Any.Type)'
  foo(type as! P.Type) // cannot invoke 'foo' with an argument list of 
type '(P.Type)'

  foo(type as! Int.Type) // works just fine
  ```

  Arguments to generic methods _must_ be statically knowable for the 
method to be dispatched; otherwise you’ll get the compiler error that 
you see.


This is also why you can’t `decode(Decodable.self)` or 
`decode(Any.self)` — those are not concrete types.
(On a side note, though, this would never be possible with the 
`Decodable` protocol. We need a concrete type to decode because values 
are otherwise ambiguous. Is `5` an `Int8`, `UInt8`, …, `Int`, `UInt`, 
…, `Int64`, `UInt64`, `Float`, or `Double`? Is `"2017-07-14"` a 
`String` or a `Date`? What would you expect to get for 
`decode(Decodable.self)`?)


— Itai

On 13 Jul 2017, at 11:46, Joanna Carter via swift-users wrote:


Greetings

I notice that, with Swift 4, I can decode an object like this :

	• let retrievedSpot = try decoder.decode(ParkingSpot.self, from: 
retrievedData)


And that will return a ParkingSpot, as expected, into retrievedSpot.

However, I thought I would try the same technique with one of my pet 
projects…


I have a protocol  and an implementing struct :

• public protocol PropertyProtocol
• {
•   static var propertyType: Any.Type { get }
•
•   var untypedValue: Any? { get }
• }
•
	• public struct Property : 
PropertyProtocol

• {
•   public static var propertyType: Any.Type
•   {
• return valueT.self
•   }
•
•   public var untypedValue: Any?
•   {
• return value
•   }
•
•   public var value = valueT()
• }

Now, I want to be able to use a "factory" method to create an instance 
of Property, bound to its parameter type. So, I followed the same 
principal as Decoder :


• struct PropertyFactory
• {
	•   static func createProperty(_ type: T.Type) -> 
PropertyProtocol where T : DefaultValueProvider

•   {
• return type.createProperty()
•   }
• }

DefaultValueProvider is defined as follows and String is extended to 
conform to it :


• public protocol DefaultValueProvider
• {
•   init()
• }
•
• extension String : DefaultValueProvider { }

Now, this works fine if I pass a known type :

• let pproperty = PropertyFactory.createProperty(String.self)

But, if I hold the type to be passed in in an Any.Type or 
DefaultValueProvider.Type variable, then doing this :


• let type: Any.Type = String.self
•
• if let propertyType = type as? DefaultValueProvider.Type
• {
•   let p = PropertyFactory.createProperty(propertyType)
•
•   …

Fails to compile with the message : Cannot invoke 'createProperty' 
with an argument list of type '(DefaultValueProvider.Type)'


Likewise Decoder.decode(…) will not accept storing the type in an 
Any.Type or Decodable.Type variable.


I find this odd and perplexing. Is this a known issue or has nobody 
yet realised that this could be useful ?


Joanna

--
Joanna Carter
Carter Consulting
___
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

Re: [swift-users] Decode a JSON object of unknown format into a Dictionary with Decodable in Swift 4

2017-07-03 Thread Itai Ferber via swift-users

Hi Kevin,

You’re right — this is one of the limitations of the box design 
here. One thing we can do is expose the underlying boxed value as a 
`KeyedDecodingContainerProtocol` existential value using an accessor on 
the box so you can down-cast.


However, it shouldn’t be necessary to add any methods to 
`_JSONEncoder` or `_JSONDecoder` to support this. What are you trying to 
do?


— Itai

On 1 Jul 2017, at 9:07, Kevin Wooten wrote:


Itai,

I tried copying JSONEncoder.swift from the swift repo and implementing 
the `Unevaluated` type in it.  It doesn’t appear to be a workable 
solution due to the fact that the `KeyedEncodingContainer` type 
erasure box is the only value returned from `container(keyedBy:)`. 
This means that any extra methods implemented inside `JSONDecoder` (or 
`_JSONDecoder` in this case) can ever be publicly accessed (even with 
casting) unless the type erasure box also includes an equivalent 
method.


How do you propose getting around this?  Seems like the design of this 
might be a bit limiting when considering extension/enhancement in user 
specific code.




On Jun 29, 2017, at 12:47 PM, Itai Ferber  wrote:

Hi Kevin,

On Jun 29, 2017, at 12:30 PM, Kevin Wooten via swift-users 
> wrote:



Hi Jon,

I just joined this mailing list and have tried to catch up on the
history of this thread, so please excuse me if I’ve missed 
something.


I’m sorry the Codable API at the moment does not answer your 
needs —
you’re clearly not the only one who’s run into this, so let’s 
see

how we can work together to make the API better for everyone.
For one thing, in the case of grabbing a subtree of JSON as
"unevaluated" or "unmapped" (as it appears to be in the metadata 
case),
it should be fairly simple to add a `JSONDecoder.UnevaluatedJSON` 
type
that will allow you to essentially decode that part of the tree as 
an
`Any`. `JSONDecoder` would have knowledge of this type and would be 
able

to return the subtree inside of it — you’d decode a property as
`JSONDecoder.UnevaluatedJSON.self` and access the contents through 
`var
value: Any?`, or something similar. This would be simple additive 
API,
which although might not make it in the upcoming betas, should be 
fairly

simple introduce. Would this solve that use case?

We’re also working on improving `NSISO8601DateFormatter`. I 
don’t
think I saw it in any of your emails — what specific use case are 
you

looking for that it doesn’t at the moment support?

— Itai



Itai,

Is this a formal solution that is going to be implemented? This 
would solve just about every issue I currently have with Decodable.
I can’t make any promises at the moment — we’ve got a lot of 
high-priority things to fix before the Swift 4.0 release. However, 
this is something I’d certainly like to put through API review and 
eventually release, since this is clearly something that would be 
beneficial to a lot of our users.



Two points…

1) Putting it on `JSONDecoder` seems dubious since you’d only have 
access to `Decoder` (although conditional casting could solve that). 
It seems adding the method to `Decoder` and using 
`Decoder.Unevaluated.self` as the requested type, would be more 
useful. A user could then conditionally cast that value to things 
like `[String: Any]` and possibly use its contents generically.
Putting that on Decoder would require all Decoders to have an 
"unevaluated type" representation, which may not be appropriate for 
all formats.
Since this is very often a request when working with 3rd-party APIs 
which you don’t control (and are rarely offered in more than one 
format, if that), putting this directly on JSONDecoder seems 
reasonable — you’d only really expect this representation if 
you’re decoding from JSON; if you’re encoding to/from a different 
format, you’re likely in control of the data in those formats.


2) Matching it with an equivalent on `Encoder` would be great as 
well.  We take in JSON that has “metaData” like one 
aforementioned exampled. We then have to send back the equivalent 
metadata during a subsequent update; without ever inspecting or 
altering the unevaluated data. Being able encode a 
`Decoder.Unevaluated` would solve that problem as well.

Yes, we’d add an equivalent type on encode as well.




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





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


Re: [swift-users] Decode a JSON object of unknown format into a Dictionary with Decodable in Swift 4

2017-06-29 Thread Itai Ferber via swift-users
Hi Kevin,

> On Jun 29, 2017, at 12:30 PM, Kevin Wooten via swift-users 
>  wrote:
> 
>> Hi Jon,
>> 
>> I just joined this mailing list and have tried to catch up on the 
>> history of this thread, so please excuse me if I’ve missed something.
>> 
>> I’m sorry the Codable API at the moment does not answer your needs — 
>> you’re clearly not the only one who’s run into this, so let’s see 
>> how we can work together to make the API better for everyone.
>> For one thing, in the case of grabbing a subtree of JSON as 
>> "unevaluated" or "unmapped" (as it appears to be in the metadata case), 
>> it should be fairly simple to add a `JSONDecoder.UnevaluatedJSON` type 
>> that will allow you to essentially decode that part of the tree as an 
>> `Any`. `JSONDecoder` would have knowledge of this type and would be able 
>> to return the subtree inside of it — you’d decode a property as 
>> `JSONDecoder.UnevaluatedJSON.self` and access the contents through `var 
>> value: Any?`, or something similar. This would be simple additive API, 
>> which although might not make it in the upcoming betas, should be fairly 
>> simple introduce. Would this solve that use case?
>> 
>> We’re also working on improving `NSISO8601DateFormatter`. I don’t 
>> think I saw it in any of your emails — what specific use case are you 
>> looking for that it doesn’t at the moment support?
>> 
>> — Itai
> 
> 
> Itai, 
> 
> Is this a formal solution that is going to be implemented? This would solve 
> just about every issue I currently have with Decodable.
I can’t make any promises at the moment — we’ve got a lot of high-priority 
things to fix before the Swift 4.0 release. However, this is something I’d 
certainly like to put through API review and eventually release, since this is 
clearly something that would be beneficial to a lot of our users.

> Two points…
> 
> 1) Putting it on `JSONDecoder` seems dubious since you’d only have access to 
> `Decoder` (although conditional casting could solve that). It seems adding 
> the method to `Decoder` and using `Decoder.Unevaluated.self` as the requested 
> type, would be more useful. A user could then conditionally cast that value 
> to things like `[String: Any]` and possibly use its contents generically.
Putting that on Decoder would require all Decoders to have an "unevaluated 
type" representation, which may not be appropriate for all formats.
Since this is very often a request when working with 3rd-party APIs which you 
don’t control (and are rarely offered in more than one format, if that), 
putting this directly on JSONDecoder seems reasonable — you’d only really 
expect this representation if you’re decoding from JSON; if you’re encoding 
to/from a different format, you’re likely in control of the data in those 
formats.

> 2) Matching it with an equivalent on `Encoder` would be great as well.  We 
> take in JSON that has “metaData” like one aforementioned exampled. We then 
> have to send back the equivalent metadata during a subsequent update; without 
> ever inspecting or altering the unevaluated data. Being able encode a 
> `Decoder.Unevaluated` would solve that problem as well.
Yes, we’d add an equivalent type on encode as well.

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

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


Re: [swift-users] Decode a JSON object of unknown format into a Dictionary with Decodable in Swift 4

2017-06-23 Thread Itai Ferber via swift-users

Hi Jon,

I just joined this mailing list and have tried to catch up on the 
history of this thread, so please excuse me if I’ve missed something.


I’m sorry the Codable API at the moment does not answer your needs — 
you’re clearly not the only one who’s run into this, so let’s see 
how we can work together to make the API better for everyone.
For one thing, in the case of grabbing a subtree of JSON as 
"unevaluated" or "unmapped" (as it appears to be in the metadata case), 
it should be fairly simple to add a `JSONDecoder.UnevaluatedJSON` type 
that will allow you to essentially decode that part of the tree as an 
`Any`. `JSONDecoder` would have knowledge of this type and would be able 
to return the subtree inside of it — you’d decode a property as 
`JSONDecoder.UnevaluatedJSON.self` and access the contents through `var 
value: Any?`, or something similar. This would be simple additive API, 
which although might not make it in the upcoming betas, should be fairly 
simple introduce. Would this solve that use case?


We’re also working on improving `NSISO8601DateFormatter`. I don’t 
think I saw it in any of your emails — what specific use case are you 
looking for that it doesn’t at the moment support?


— Itai

On 23 Jun 2017, at 9:24, Jon Shier via swift-users wrote:


David:
	I never called the design silly (though I think it’s inadequate for 
some important usage and makes some strange decisions), I was 
referring to the fact that the (apparent) official solution can’t 
actually decode all of the JSON people use. It’s the same reason I 
brought up NSISO8601DateFormatter. After years of using third party 
libraries or writing your own, limited, implementation, finally, 
finally there was an official solution from Apple. The official 8601 
date formatter. Only, come to find out, it doesn’t actually handle 
all of 8601 and those third party libraries or custom implementations 
are still required if you venture outside supported scenarios. I’m 
concerned about the same thing happening here. Now, if JSONDecoder 
isn’t actually intended to serve as a general JSON parsing solution, 
which I think would be surprising to a lot people, then fair enough. 
Apple and the Swift team just need to be far more clear that that’s 
the case, rather letting everyone believe otherwise. And frankly, if 
that’s the case, I think a huge opportunity has been missed. At the 
same time, if / when an official solution for JSON parsing comes out, 
or an actual JSON representation, how will it interact with the 
previous implementation?
	These concerns, and the general concerns I expressed during the 
evolution review (which still exist) aside, this is fixable, if the 
Swift team is interested in doing so. However, if the limitations of 
JSONDecoder aren’t even seen as limitations, or interest in fixing 
them aren’t there, then there’s little point to continuing the 
discussion. Something as simple as an additional decode(_ type: from: 
Any) on JSONDecoder would solve the issues with decoding partially 
deserialized blobs or representations from other APIs. Something to 
help represent Any in Codable types might be useful, though I 
recognize that there isn’t any way to currently differentiate 
between Codable types and those just used by JSON.
	All of that said, my concerns mainly lie within the JSON realm. 
Codable works great for serialization to disk or other scenarios where 
I can just deal with the Data result and not have to worry about 
weakly typed intermediate results. I’ll certainly be using it 
everywhere I can. And I’m super happy that conformance is generated 
by the compiler rather than manually, like we had to do with 
Objective-C for over a decade. Even the JSON side is useful if I can 
control both sides of the API, which makes Swift on the server very 
powerful.
	So if I seem overly strident in my expression here it’s because I 
experience the pain of consuming poorly designed JSON in Swift on 
practically a daily basis and had hoped that a native implementation 
would alleviate that. That it doesn’t, for me and others, currently, 
is very disappointing. That the Swift team doesn’t seem to see the 
current limitations as important or at all is doubly so, since it 
seems like these issues will never be fixed.




Jon



On Jun 23, 2017, at 4:34 AM, David Hart  wrote:


On 23 Jun 2017, at 03:45, Jon Shier via swift-users 
> wrote:


	I’m sorry, are you complaining about my use of Codable instead of 
more precisely referring to the JSON endcode/decode functionality 
based on it in Foundation, or are you honestly trying to say that 
said functionality was never intended to be a general purpose JSON 
solution? If it’s not actually intended to handle all JSON you 
should probably call it something else.


Hi Jon,

First of all, I'd like to point out that I've found your tone to be 
quite rude. Calling the design of Codable, that has gotten a lot