refined icon indicating copy to clipboard operation
refined copied to clipboard

Add operations on refined typed

Open cvogt opened this issue 9 years ago • 9 comments

Would be great to have a subset of the same operations available on unconstrained typed also available on refined types but tracking properties across operations. Even a small subset would probably already be a big win. I am thinking things like:

scala> val a: Int Refined Greater[W.`5`.T] = 10
scala> a + 1
res0: Int Refined Greater[W.`6`.T]

Are there any operations like this already? If not, adding a few to open the door for contributions in the same style might be a good way to get started.

cvogt avatar Nov 02 '16 13:11 cvogt

:+1: As always, a typeclass-based approach would be the best approach.

dwijnand avatar Nov 02 '16 13:11 dwijnand

:+1: Operations like these are not in the library yet, but they would be a welcome addition. It was brought up before on Gitter by @howyp who also started working on this - unfortunately I had not yet time look at it in detail. :-(

fthomas avatar Nov 02 '16 20:11 fthomas

I'm not sure a constrained + unconstrained should gives us a constrained type. Perhaps you mean constrained + literal ?

soronpo avatar Nov 04 '16 16:11 soronpo

I agree this would be a great thing to have. I've done some of the ground-work for it, I'll see if I can get a PR raised (even if it's just for review rather than expecting a merge) in the next week or so.

howyp avatar Nov 04 '16 16:11 howyp

@soronpo How about somethingWithKnownProperties + somethingElseWithKnownProperties should give somethingWithWhateverPropertiesWeCanDerive. Literals have known properties, refined types have known properties, any number type than Long also has some known limited ranges we know. We obviously do not have to aim for completeness right away.

@howyp sounds great :)!

cvogt avatar Nov 04 '16 19:11 cvogt

IIRC there are issues here, for instance numerical types wrap from positive to negative (and/or vice versa).

dwijnand avatar Nov 04 '16 19:11 dwijnand

I don't know refined well at all. Obviously we can only derive properties that can be represented in refined.

cvogt avatar Nov 04 '16 19:11 cvogt

eg.

scala> Int.MaxValue
res0: Int = 2147483647

scala> Int.MaxValue + 1
res1: Int = -2147483648

dwijnand avatar Nov 04 '16 20:11 dwijnand

With the addition of "companions" for predefined refined types there is now a suitable place for operations with these types. For example, I experimented with addition of NonNegInts here: https://github.com/fthomas/refined/blob/76d812c3508e45e6413914dd76a81908ae5cf1db/modules/core/shared/src/main/scala/eu/timepit/refined/types/numeric.scala#L19-L28 Which preserve the non-negative property even in case of overflows:

scala> NonNegInt.MaxValue
res1: eu.timepit.refined.types.all.NonNegInt = 2147483647

scala> NonNegInt.plus(NonNegInt.MaxValue, NonNegInt(1))
res2: eu.timepit.refined.types.all.NonNegInt = 0

scala> NonNegInt.plus(NonNegInt.MaxValue, NonNegInt(2))
res3: eu.timepit.refined.types.all.NonNegInt = 1

fthomas avatar Jan 13 '18 19:01 fthomas