Should we make a clear value-level distinction between floating and integral numbers?
- Dominant language
- Haskell
- Stars
- 1.3k
- Forks
- 336
- Avg merge
- 3d 7h
- Merged PRs (30d)
- 4
Description
This basic subject has been variously discussed before –
https://github.com/bos/aeson/issues/227
https://github.com/bos/aeson/issues/181
The thing is that Aeson can't make a distinction between integer values and floating-point values (scientific values) which merely happen to be equal to an integer.
```
Prelude Data.Aeson> encode 4
"4"
Prelude Data.Aeson> encode 4.0
"4"
Prelude Data.Aeson> encode 4e+30
"4000000000000000000000000000000"
Prelude Data.Aeson> encode 4.53986e+30
"4539860000000000000000000000000"
```
The former two may be sensible enough. The latter are kinda _correct_ too, at least in a dynamically-typed understanding of numbers; but they're arguably not desirable. It's most obvious when interpreting JSON as a human-readable format, as the [aeson-pretty](http://hackage.haskell.org/package/aeson-pretty) library does. There, this behaviour [is under discussion right now](https://github.com/informatikr/aeson-pretty/issues/22). In science, numbers like `4.53986e+30` are very much not something unusual, and nobody would consider it acceptable to print them in expanded, exact integer form if the purpose is human readability.
Now, it's understood that Aeson itself does _not_ really focus on human readability, but even so, such insignificant-digit-monsters are a bit of a pain. The space usage and parsing overhead can't be completely irrelevant.
Dynamic languages like Python actually make a distinction between integers and integral-floats in JSON:
```python
Python 3.4.3 (default, Nov 17 2016, 01:08:31)
Type "copyright", "credits" or "license" for more information.
IPython 4.0.1 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1]: import json
In [5]: json.dumps(4)
Out[5]: '4'
In [6]: json.dumps(4.0)
Out[6]: '4.0'
In [7]: json.dumps(4e+32)
Out[7]: '4e+32'
```
Aeson used to have such a distinction too: before aeson-0.7, `Number` used [`Data.Attoparsec.Number`](http://hackage.haskell.org/package/attoparsec-0.10.4.0/docs/Data-Attoparsec-Number.html#t:Number), which has separate cases. Now granted, this can lead to some problems too
https://github.com/sol/aeson-qq/issues/4
but I think all in all I think we should follow Python here. So would it be viable to try something like
```haskell
data Value = Object !Object
| Array !Array
| String !Text
| Scientific !Scientific
| Int !Int
| Bool !Bool
| Null
deriving (Eq, Read, Show, Typeable, Data)
```
to have a clear grasp of which numbers are really integers and which ones are merely _within experimental error in the range of an integer_?
Contributor guide
Assessment
This issue has not been assessed yet.