dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.06k stars 1.56k forks source link

JsonEncoder: can't serialize NaNs with customized encoder, because of wrong identical(NaN,NaN) behavior #35165

Open ajsergeev opened 5 years ago

ajsergeev commented 5 years ago

We are using customized JSON Encoder to serialize NaN. Now we moving to dart2 from dart1 and I faced this issue: 1) encoder = new JsonEncoder(_encoder); 2) static dynamic _encoder(value) { if (value is num) { num n = value; if (n.isNaN) { return 'NaN'; } } } 3) _encoder method works ok 3) Finally, writeObject() calls _removeSeen() method, which relies on identical. As both parameters are NaNs for identical, it fails and overall process fails, see screenshots attached.


lrhn commented 5 years ago

This is a known, and old, bug in dart2js (#11551). Closing this issue as a duplicate of that bug.

The identity on doubles is defined as comparing the bit-representation as IEEE-754 64-bit floating points, which would make a NaN identical to itself (but not necessarily to another NaN).

Dart2js uses JavaScript === for identity, which differs from the required behavior on NaN (not identical to itself) and identical(0.0, -0.0) which wrongly returns true.

ajsergeev commented 5 years ago

I'm not about identical. Your JSON Encoder customization doesn't work and I don't see a good way to fix it. Yes, it's because of identical, but if it's impossible to fix identical, you must provide a way to customize identical for encoder or don't use identical at all there, otherwise toEncodable parameter is useless and doesn't work!

ajsergeev commented 5 years ago

I understand I can preprocess Map and fix all NaNs before call to Encoder (this is my temp workaround for this), but it's not good way to solve this and if dart pretend to good architecture it must be solved a better way.

lrhn commented 5 years ago

I see. So even if the problem really is identical, we should make sure that our jsonEncoder doesn't actually depend on identical in that case.

ajsergeev commented 5 years ago

yes, that might solve this, thanks!

joe776 commented 5 years ago

I'm not sure if it is related, but we ran into a very similar problem. The following code works with dart2js (and DartPad), but fails when run via dartdevc:

  print(json.encode(double.nan, toEncodable: (_) => 'NaN'));
  print(json.encode([double.nan], toEncodable: (_) => 'NaN'));
  print(json.encode({'foo': [double.nan]}, toEncodable: (_) => null));

Code is also here: https://dartpad.dartlang.org/0bf3d37cc6773abf233843556af973a4

So for me it looks like dart2js actually does work, but dartdevc fails?