<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/xhtml; charset=utf-8">
</head>
<body>
<div style="font-family:sans-serif"><div style="white-space:normal">
<p dir="auto">Hi Evtim,</p>

<p dir="auto">Just want to give some context for this.<br>
This is due to the fact that <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7">JSONEncoder</code> and <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7">JSONDecoder</code> are currently based on <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7">JSONSerialization</code>: when you go to decode some JSON data, the data is deserialized using <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7">JSONSerialization</code>, and then decoded into your types by <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7">JSONDecoder</code>. At the <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7">JSONSerialization</code> level, however, there is no way to know whether a given numeric value is meant to be interpreted as a <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7">Double</code> or as a <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7">Decimal</code>.</p>

<p dir="auto">There are subtle differences to decoding as either, so there is no behavior that could satisfy all use cases. <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7">JSONSerialization</code> has to make a decision, so if the number could fit losslessly in a <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7">Double</code>, it will prefer that to a <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7">Decimal</code>. This allows guaranteed precise round-tripping of all <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7">Double</code> values at the cost of different behavior when decoding a <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7">Decimal</code>.</p>

<p dir="auto">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?</p>

<p dir="auto">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 <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7">String</code>, then convert into a <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7">Decimal</code> where you need it, e.g.</p>

<pre style="background-color:#F7F7F7; border-radius:5px 5px 5px 5px; margin-left:15px; margin-right:15px; max-width:90vw; overflow-x:auto; padding:5px; color:black" bgcolor="#F7F7F7"><code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0" bgcolor="#F7F7F7"><span style="color: #008800; font-weight: bold">import</span> <span style="color: #BB0066; font-weight: bold">Foundation</span>

<span style="color: #008800; font-weight: bold">struct</span> <span style="color: #BB0066; font-weight: bold">Foo</span> : Codable {
    <span style="color: #008800; font-weight: bold">var</span> <span style="color: #996633">number</span>: Decimal

    <span style="color: #008800; font-weight: bold">public</span> <span style="color: #008800; font-weight: bold">init</span>(number: Decimal) {
        <span style="color: #008800; font-weight: bold">self</span>.number = number
    }

    <span style="color: #008800; font-weight: bold">private</span> <span style="color: #008800; font-weight: bold">enum</span> <span style="color: #BB0066; font-weight: bold">CodingKeys</span> : <span style="color: #007020">String</span>, CodingKey {
        <span style="color: #008800; font-weight: bold">case</span> number
    }

    <span style="color: #008800; font-weight: bold">public</span> <span style="color: #008800; font-weight: bold">init</span>(from decoder: Decoder) throws {
        <span style="color: #008800; font-weight: bold">let</span> <span style="color: #996633">container</span> = try decoder.container(keyedBy: CodingKeys.<span style="color: #008800; font-weight: bold">self</span>)
        <span style="color: #008800; font-weight: bold">let</span> <span style="color: #996633">stringValue</span> = try container.decode(<span style="color: #007020">String</span>.<span style="color: #008800; font-weight: bold">self</span>, forKey: .number)
        guard <span style="color: #008800; font-weight: bold">let</span> <span style="color: #996633">decimal</span> = Decimal(string: stringValue) <span style="color: #008800; font-weight: bold">else</span> {
            throw DecodingError.dataCorruptedError(forKey: .number, <span style="color: #008800; font-weight: bold">in</span>: container, debugDescription: <span style="background-color: #fff0f0">"Invalid numeric value."</span>)
        }

        <span style="color: #008800; font-weight: bold">self</span>.number = decimal
    }

    <span style="color: #008800; font-weight: bold">public</span> <span style="color: #008800; font-weight: bold">func</span> <span style="color: #0066BB; font-weight: bold">encode</span>(to encoder: Encoder) throws {
        <span style="color: #008800; font-weight: bold">var</span> <span style="color: #996633">container</span> = encoder.container(keyedBy: CodingKeys.<span style="color: #008800; font-weight: bold">self</span>)
        try container.encode(<span style="color: #008800; font-weight: bold">self</span>.number.description, forKey: .number)
    }
}


<span style="color: #008800; font-weight: bold">let</span> <span style="color: #996633">foo</span> = Foo(number: Decimal(string: <span style="background-color: #fff0f0">"2.71828182845904523536028747135266249775"</span>)<span style="color: #333333">!</span>)
<span style="color: #007020">print</span>(foo) <span style="color: #888888">// =&gt; Foo(number: 2.71828182845904523536028747135266249775)</span>

<span style="color: #008800; font-weight: bold">let</span> <span style="color: #996633">encoder</span> = JSONEncoder()
<span style="color: #008800; font-weight: bold">let</span> <span style="color: #996633">data</span> = try encoder.encode(foo)
<span style="color: #007020">print</span>(<span style="color: #007020">String</span>(data: data, encoding: .utf8)<span style="color: #333333">!</span>) <span style="color: #888888">// =&gt; {"number":"2.71828182845904523536028747135266249775"}</span>

<span style="color: #008800; font-weight: bold">let</span> <span style="color: #996633">decoder</span> = JSONDecoder()
<span style="color: #008800; font-weight: bold">let</span> <span style="color: #996633">decoded</span> = try decoder.decode(Foo.<span style="color: #008800; font-weight: bold">self</span>, from: data)
<span style="color: #007020">print</span>(decoded) <span style="color: #888888">// =&gt; Foo(number: 2.71828182845904523536028747135266249775)</span>

<span style="color: #007020">print</span>(decoded.number == foo.number) <span style="color: #888888">// =&gt; true</span>
</code></pre>



<p dir="auto">— Itai</p>

<p dir="auto">On 28 Oct 2017, at 11:23, Evtim Papushev via swift-users wrote:</p>

</div>
<div style="white-space:normal"><blockquote style="border-left:2px solid #777; color:#777; margin:0 0 5px; padding-left:5px"><p dir="auto">Hello :)<br>
<br>
I am trying to find a way to parse a number as Decimal without losing the number's precision.<br>
<br>
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.<br>
<br>
Does anyone know if there is a way to obtain the raw data for this specific field so I can write the conversion code?<br>
<br>
Thanks,<br>
Evtim<br>
<br>
_______________________________________________<br>
swift-users mailing list<br>
swift-users@swift.org<br>
<a href="https://lists.swift.org/mailman/listinfo/swift-users" style="color:#777">https://lists.swift.org/mailman/listinfo/swift-users</a></p>
</blockquote></div>
<div style="white-space:normal">
</div>
</div>
</body>
</html>