refined
refined copied to clipboard
`Greater[5] Or Equal[5]` results in drastic performance problems with `unsafeFrom`
Running the following takes more than a minute to complete for me:
type Crazy = Int Refined (Greater[5] Or Equal[5])
object Crazy extends RefinedTypeOps.Numeric[Crazy, Int]
val crazy = Crazy.unsafeFrom(5)
However, the following is fine:
val sane: Crazy = refineV[Greater[5] Or Equal[5]](5).toOption.get
Here is a scastie demonstrating the problem:
https://scastie.scala-lang.org/oGPpPS59RcG8ejX9dSDhhQ
It just gets closed
, but when run locally it will eventually return.
I have tried refined versions 0.9.29
through 0.10.2
and scala versions 2.13.8
and 3.2.2
I suspect that calculating MinValue
and MaxValue
of Crazy
is the culprit.
That was quick!
I should have mentioned in the comment, Equal[5] Or Greater[5]
is fine.
It seems @fthomas suspicions are correct. This does it:
object Main extends App {
type Crazy = Int Refined (Greater[5] Or Equal[5])
val min: Min[Crazy] = implicitly[Min[Crazy]]
}
Oh Or
is going to use Min.validateMin
which will start at Int.MinValue
and step up one at a time until it finds a valid value. No wonder.
Would something like this work?
implicit def orMin[F[_, _], T, L, R](implicit
rt: RefType[F],
ml: Min[F[T, L]],
mr: Min[F[T, R]],
at: Adjacent[T],
v: Validate[T, L Or R]
): Min[F[T, L Or R]] =
Min.instance(rt.unsafeWrap(findValid(at.min(rt.unwrap(ml.min), rt.unwrap(mr.min)))))
Would something like this work?
Yes, I think so. But since this is Or
, the findValid
call should not be needed.
Oh good point. I realised that still isn't going to cut it. There isn't one for Equal
.
This seems to fix it:
implicit def orMin[F[_, _], T, L, R](implicit
rt: RefType[F],
ml: Min[F[T, L]],
mr: Min[F[T, R]],
at: Adjacent[T],
v: Validate[T, L Or R]
): Min[F[T, L Or R]] =
Min.instance(rt.unsafeWrap(at.min(rt.unwrap(ml.min), rt.unwrap(mr.min))))
implicit def equalMin[F[_, _], T, N](implicit
rt: RefType[F],
wn: WitnessAs[N, T]
): Min[F[T, Equal[N]]] =
Min.instance(rt.unsafeWrap(wn.snd))
It probably makes sense to add these two instances for Min
and Max
.
On a side note: The built-in GreaterEqual[N]
should be preferred over Greater[N] Or Equal[N]
.
On a side note: The built-in
GreaterEqual[N]
should be preferred overGreater[N] Or Equal[N]
.
Agreed. I found this example/problem in a different library and I'm putting in a PR to do just that. 😄