<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>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.&nbsp;<div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>That said, I appreciate the support given Codable on this list.</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">Jon</div><div class=""><div><br class=""><blockquote type="cite" class=""><div class="">On Oct 31, 2017, at 1:07 PM, Itai Ferber via swift-users &lt;<a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class="">


<meta http-equiv="Content-Type" content="text/xhtml; charset=utf-8" class="">

<div class="">
<div style="font-family:sans-serif" class=""><div style="white-space:normal" class=""><p dir="auto" class="">Hi Evtim,</p><p dir="auto" class="">Just want to give some context for this.<br class="">
This is due to the fact that <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">JSONEncoder</code> and <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">JSONDecoder</code> are currently based on <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">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" class="">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" class="">JSONDecoder</code>. At the <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">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" class="">Double</code> or as a <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">Decimal</code>.</p><p dir="auto" class="">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" class="">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" class="">Double</code>, it will prefer that to a <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">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" class="">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" class="">Decimal</code>.</p><p dir="auto" class="">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" class="">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" class="">String</code>, then convert into a <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">Decimal</code> where you need it, e.g.</p>

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

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

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

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

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

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

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


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

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

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

<span style="color: #007020" class="">print</span>(decoded.number == foo.number) <span style="color: #888888" class="">// =&gt; true</span>
</code></pre><p dir="auto" class="">— Itai</p><p dir="auto" class="">On 28 Oct 2017, at 11:23, Evtim Papushev via swift-users wrote:</p>

</div>
<div style="white-space:normal" class=""><blockquote style="border-left:2px solid #777; color:#777; margin:0 0 5px; padding-left:5px" class=""><p dir="auto" class="">Hello :)<br class="">
<br class="">
I am trying to find a way to parse a number as Decimal without losing the number's precision.<br class="">
<br class="">
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 class="">
<br class="">
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 class="">
<br class="">
Thanks,<br class="">
Evtim<br class="">
<br class="">
_______________________________________________<br class="">
swift-users mailing list<br class="">
<a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a><br class="">
<a href="https://lists.swift.org/mailman/listinfo/swift-users" style="color:#777" class="">https://lists.swift.org/mailman/listinfo/swift-users</a></p>
</blockquote></div>
<div style="white-space:normal" class="">
</div>
</div>
</div>

_______________________________________________<br class="">swift-users mailing list<br class=""><a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-users<br class=""></div></blockquote></div><br class=""></div></body></html>