-
Notifications
You must be signed in to change notification settings - Fork 158
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
Fix #396 by avoiding .toDouble in Modulo Validate #398
Conversation
Codecov Report
@@ Coverage Diff @@
## master #398 +/- ##
==========================================
- Coverage 96.63% 96.16% -0.48%
==========================================
Files 43 43
Lines 505 521 +16
Branches 10 11 +1
==========================================
+ Hits 488 501 +13
- Misses 17 20 +3
Continue to review full report at Codecov.
|
LGTM, thanks @howyp! I think the MiMa exclusions are fine, since the Any specific reasons for dropping the |
i: Integral[T] | ||
): Validate.Plain[T, Modulo[N, O]] = | ||
Validate.fromPredicate( | ||
t ⇒ i.rem(t, i.fromInt(tn())) == to(), |
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.
to()
should be i.fromInt(to())
so that we don't compare unrelated types.
I know the JVM supports modulus on floating-point values, so in some sense it's a meaningful thing for refined to support. But for evaluating even/oddness it gives unexpected results once you get into large numbers: scala> refineV[Even](Double.MaxValue)
res8: Either[String,eu.timepit.refined.api.Refined[Double,eu.timepit.refined.numeric.Even]] = Right(1.7976931348623157E308)
scala> refineV[Even](Double.MaxValue - 1)
res9: Either[String,eu.timepit.refined.api.Refined[Double,eu.timepit.refined.numeric.Even]] = Right(1.7976931348623157E308) |
That seems correct, given scala> Double.MaxValue == (Double.MaxValue - 1)
res8: Boolean = true As long as the instances are consistent with |
Maybe I just have a dislike of the weirdness of operations on floating-point numbers :-( Let me know if you'd rather move this discussion to Gitter/another issue, the PR is GTG from my point of view. I think if you're using the If you're keen on keeping the support for floating-points with refineV[Even](2.0)
res0: Either[String,eu.timepit.refined.api.Refined[Double,eu.timepit.refined.numeric.Even]] = Right(2.0)
scala> refineV[Even](2.1)
res1: Either[String,eu.timepit.refined.api.Refined[Double,eu.timepit.refined.numeric.Even]] = Left(Predicate failed: (2.1 % 2 == 0).)
scala> refineV[Even](1.9)
res2: Either[String,eu.timepit.refined.api.Refined[Double,eu.timepit.refined.numeric.Even]] = Left(Predicate failed: (1.9 % 2 == 0).)
scala> refineV[Odd](1.0)
res3: Either[String,eu.timepit.refined.api.Refined[Double,eu.timepit.refined.numeric.Odd]] = Right(1.0)
scala> refineV[Odd](1.1)
res4: Either[String,eu.timepit.refined.api.Refined[Double,eu.timepit.refined.numeric.Odd]] = Right(1.1)
scala> refineV[Odd](0.9)
res5: Either[String,eu.timepit.refined.api.Refined[Double,eu.timepit.refined.numeric.Odd]] = Right(0.9) I found that behaviour quite surprising. Would |
You've convinced me. Even and odd only have a precise definition for integers and the choice refined makes for floating point types will always be arbitrary because there is no common definition what odd and even means for floats. And since we have defined 👍 for dropping those instances. |
Excellent! The instances have gone. Let me know if anything else is needed on this |
Everything was fine. Thanks again for your patience. :-) |
Fixes #396.
This switches the
Validate
instances forModulo
to useIntegral
rather thanNumeric
. I've also kept the support for floating point types by having specific instances for them, though I'd vote for dropping this support.I couldn't find a way to create a witness-style singleton for
Byte
andShort
literals - hence they are not tested.The change is almost binary-compatible. I've had to add an exclude for
ReversedMissingMethodProblem
- is that ok? I see there are other exclusions of this type already.