Skip to content
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 operations on refined typed #217

Open
cvogt opened this issue Nov 2, 2016 · 9 comments
Open

Add operations on refined typed #217

cvogt opened this issue Nov 2, 2016 · 9 comments

Comments

@cvogt
Copy link

cvogt commented Nov 2, 2016

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.

@dwijnand
Copy link
Contributor

dwijnand commented Nov 2, 2016

👍 As always, a typeclass-based approach would be the best approach.

@fthomas
Copy link
Owner

fthomas commented Nov 2, 2016

👍 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. :-(

@soronpo
Copy link

soronpo commented Nov 4, 2016

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

@howyp
Copy link
Contributor

howyp commented Nov 4, 2016

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.

@cvogt
Copy link
Author

cvogt commented Nov 4, 2016

@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 :)!

@dwijnand
Copy link
Contributor

dwijnand commented Nov 4, 2016

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

@cvogt
Copy link
Author

cvogt commented Nov 4, 2016

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

@dwijnand
Copy link
Contributor

dwijnand commented Nov 4, 2016

eg.

scala> Int.MaxValue
res0: Int = 2147483647

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

@fthomas
Copy link
Owner

fthomas commented Jan 13, 2018

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:

object NonNegInt extends RefinedTypeOps.Numeric[NonNegInt, Int] {
def plus(x: NonNegInt, y: NonNegInt): NonNegInt =
Refined.unsafeApply(unsign(x.value + y.value))
def minus(x: NonNegInt, y: NonNegInt): NonNegInt =
Refined.unsafeApply(unsign(x.value - y.value))
private def unsign(i: Int): Int = (i << 1) >>> 1
}

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants