-
Notifications
You must be signed in to change notification settings - Fork 204
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
Add :float
support
#1055
Add :float
support
#1055
Conversation
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.
Self-review comments 📖
(defn parse-float [s] | ||
#?(:clj | ||
(if (string? s) | ||
(try | ||
(Float/parseFloat s) | ||
(catch NumberFormatException _ nil)) | ||
(throw (IllegalArgumentException. | ||
(str "Expected string, got " (if (nil? s) "nil" (-> s class .getName)))))) | ||
:cljs | ||
(parse-double s))) | ||
|
||
(defn -string->float [x] | ||
(if (string? x) | ||
(or (parse-float x) x) | ||
x)) | ||
|
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.
Here I'm providing a custom definition for parsing floats from strings. I could not find a function that used Float/parseFloat
in this way, so I copied and modified a similar function from Clojure source code.
Oh I see, I misread the docs. Do we even need to specify the bounds on cljs since it looks like the same as double?
-------- Original Message --------
…On May 17, 2024, 05:44, Sean Hagstrom wrote:
@seanstrom commented on this pull request.
---------------------------------------------------------------
In [src/malli/generator.cljc](#1055 (comment)):
> @@ -454,6 +454,20 @@
{:infinite? (get props :gen/infinite? false)
:NaN? (get props :gen/NaN? false)})
(-min-max schema options))))
+(defmethod -schema-generator :float [schema options]
+ (let [max-float #?(:clj Float/MAX_VALUE :cljs (.-MAX_VALUE js/Number))
+ min-float #?(:clj Float/MIN_VALUE :cljs (.-MIN_VALUE js/Number))
Do we want the min-float to be a negative number? Because I think (.-MIN_VALUE js/Number) would be [the smallest positive number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MIN_VALUE#description).
—
Reply to this email directly, [view it on GitHub](#1055 (comment)), or [unsubscribe](https://github.com/notifications/unsubscribe-auth/AACGFJF3HTOJIGOJDQ7BWMLZCXNRRAVCNFSM6AAAAABHQPRGQGVHI2DSMVQWIX3LMV43YUDVNRWFEZLROVSXG5CSMV3GSZLXHMZDANRSHE4DENJXGY).
You are receiving this because you commented.Message ID: ***@***.***>
|
Yeah good point, we probably don't need to do it, so I've changed it to only set the bounds for the clj and allow cljs to behave as doubles. I've also made sure to allow for infinity to be generated for cljs too. |
9a99ef2
to
58619fb
Compare
Would like to merge this, but not 100% sure if everything is resolved. What do you think @frenchy64 ? |
IMO it's a bit inconsistent with the rest of malli that the bounds are clamped on behalf of the user in the generator. Otherwise the rest looks good. |
Happy to make more changes to this PR, though I'm not sure if I understand the suggestions. I mentioned in an earlier comment that there was a reason to clamp the bounds by default when generating floats. The main reason is that calling Here's an example error message:
To avoid these exceptions I've included the default clamping of the bounds, because it would seem unstable to accidentally generate exceptions in test suites. There may be another way of avoiding exceptions, if so let's discuss some alternatives. |
One thing to note, I've recently seen this documentation on MDN about creating 32-bit floats with
|
Based on some Java documentation, it seems we can use the Based on that these two functions behave similarly and support 32-bit floats on both CLJ and CLJS, I'll try moving forward with using both of these techniques when generating |
Are there other examples of truncation in malli that you are following? To my taste this should mirror bounding a double with a bigint, what happens there? Or a hypothetical bytes generator.
I think it would be nice for the distribution of the generator to correspond to the bounds provided by the user and for the generator to always return a float. If the distribution is not possible like lower bound being too small or even nonsensical like between Double/MIN_VALUE and Double/MIN_VALUE+1, throw.
…-------- Original Message --------
On 6/11/24 10:18, Sean Hagstrom wrote:
Based on some Java documentation, it seems we can use [the .floatValue method on a double in Java](https://developer.android.com/reference/java/lang/Double#floatValue()). This seems to something similar to Math.fround where it reduces the data of the 64-bit float into a 32-bit float. It also seems to return Infinity and -Infinity for numbers that are out of the minimum and maximum range.
Based on that these two functions behave similarly and support 32-bit floats on both CLJ and CLJS, I'll try moving forward with using both of these techniques when generating :floats in Malli.
—
Reply to this email directly, [view it on GitHub](#1055 (comment)), or [unsubscribe](https://github.com/notifications/unsubscribe-auth/AACGFJFCWZTWIDIPZPF7PADZG4IKXAVCNFSM6AAAAABHQPRGQGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCNRRGAZDONRQGY).
You are receiving this because you were mentioned.Message ID: ***@***.***>
|
I suppose my thought process is around: "what does it mean to generate a float"? I would like to avoid throwing exceptions by default, which is what happens now if we don't include the clamped boundaries. The test suite for running the malli float generator will create errors because of the thrown exceptions. I could specify the boundaries in the tests when using the float generator, but that would mean each time we go to use the float generator we would need to specify the default range of 32-bit floats. And that would seem tedious since we know the default range of a 32-bit float.
Are you asking what would happen if we try to coerce a BigInt into a 64-bit double? If so, the behaviour would be to create a double that has as much precision as it can allow, or otherwise return Infinity or -Infinity. Here's some related documentation: https://www.javatpoint.com/java-biginteger-doublevalue-method
If someone inputs min/max boundaries that are outside the range/magnitude of the 32-bit float then sure we can decide to throw. However, I don't think we should throw by default when the boundaries are not specified. Based on your notes, I think we can agree that we should throw when the user provides boundaries that are unsupported by 32-bit floats. Can we also agree that we don't want to throw exceptions when no boundaries are provided to the float generator? |
Exactly. |
Okay great! I've pushed up a commit with that change, when you have a moment can you confirm that it's okay please 🙏 |
Thanks @seanstrom for doing and @frenchy64 for the review 🙇 |
Summary
:float
support as described in There's no:float
#722Notes
float
between Clojure and ClojureScript. Specifically, I've tried to make Malli to treat floats as Java/Clojure floats (instances ofFloat
) while usingclj
, and fallback todoubles
while usingcljs