-
Notifications
You must be signed in to change notification settings - Fork 106
Document protocol implementations #220
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,7 +19,7 @@ jobs: | |
| elixir: 1.8.2 | ||
| otp: 20.3.x | ||
| - pair: | ||
| elixir: 1.17.x | ||
| elixir: 1.18.x | ||
| otp: 27.x | ||
| lint: lint | ||
| steps: | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know we can't directly use
Decimal.to_string/1but the precision loss via float shouldn't be assumed acceptable. If we had aDecimal.finite?/1orDecimal.number?/1function this example could be more accurate:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I follow. I believe this is Eric's and mine point all along.
In any case, sure, we could add something like the following to the example encoder.
However,
Decimal.to_string("1.00") #=> "1.00"and that is not the result we want.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay I see what you mean by the
1.00example. But let's say you want to encodeDecimal.div(1, 3). You will lose quite a few decimal places when you convert to a 64-bit float first...There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am misunderstanding something or we are talking past each other. Yes, we are losing precision, that's why we want to use strings not floats!
Same with Deno:
I don't see the point of encoding to a higher precision something that is expected to be a float. My understanding is decoders convert to float and lose that precision anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we're basically talking about the same thing, but your intention is now clearer to me.
Since the default (protocol impl) behaviour is to encode a
Decimalas a string, isn't the point of overriding the protocol encoder in the example to show how to encode it as a JSON number instead? If the client you intend to send the JSON to, cannot handle JSON floats properly, it would of course not make any sense to do that. So we normally would do that when the API requires it or we want to store floats in a database JSON column.If you return a string like
"0.3333333333333333333333333333"in the encoder function it will become a JSON float. No problem there unless you have to parse it with JS. But even in Elixir you will get an inaccurate float, unless you provide the:floatoption and construct a Decimal usingDecimal.new/1.I hope I could clear the confusion. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have examples on JSON implementations that can decode literal JSON floats lossless? My understanding is that most implementations, including Elixir which we are using in the example here, would decode it as lossy IEEE 754 float.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think implementations would decode as floats by default but at least in ruby you can opt-in:
but yeah. maybe cd6aa59 is a mistake because I have a feeling it will cause confusion to most people. The purpose of this piece of documentation is not to educate people on subtleties of having or not having IEEE 754 but to show that we can customize encoding. @ericmj feel free to revert cd6aa59, I'm done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Json itself is actually quite unaware of floats. It just has arbitrary presision numbers being a text based format. It completely depends on the parser or encoder to deal with how to map between runtime level number values and their json text representation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think what we have now is enough. By default we have a safe arbitrary precision encoding using strings, we also have examples of custom encoding to IEEE 754 floats in the docs, and this example can of course be tweaked to whatever precision encoding you want.
Thank you @wojtekmach for the protocol implementation and documentation improvements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @wojtekmach for adjusting the example.
I think the example doesn't need to give a complete education but it should make sense. And the only good reason to override the protocol encoder is the need to do something different than the default. I don't see how the adjusted example could be confusing. I'm sure it's helpful for developers to know that you can output lossless JSON floats if required.
To cover a more general case for overriding protocol encoders, an example could be included in the Elixir documentation for
JSON.encode!/2. There isn't one currently.Wojteck already gave an example with Ruby. In the issue #219 referenced by this PR, I mentioned a few other languages that can do lossless decoding and encoding. Afaics, JS is probably the only major language that isn't capable of doing this.
Thanks for the improvements. 👍