-
Notifications
You must be signed in to change notification settings - Fork 98
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
Inconsistent Range behavior when dealing with reverse ranges #564
Comments
I would say it is by design:
That said, I personally find such an approach controversial quite a bit. |
Yes, this is one of the things I think we should consider changing for 1.0. See my comment in #277 (comment). Indeed, this design was rejected for the new HashMap and HashSet, on grounds of be a "Haskell cargo-cult". So at the very least, this library now has inconsistent designs. |
If we could change that, then perhaps it would be a cool change. Would we consider making |
See also some discussion in #315 (comment). |
Just to clarify, are we saying that we intentionally want the usage of non-coherent instances to be normative? Like, we demand either Using scala> val sillyButValidHash: Hash[Int] = new Hash[Int] { override def hash(a: Int): Int = 1; override def eqv(x: Int, y: Int): Boolean = Eq[Int].eqv(x, y)}
sillyButValidHash: cats.Hash[Int] = $anon$1@1f21f982
scala> HashSet(1) === HashSet(1)(sillyButValidHash)
res0: Boolean = true
scala> HashSet(1).add(2) === HashSet(1)(sillyButValidHash).add(2)
res1: Boolean = false
scala> HashSet(1).add(2).iterator.toList === HashSet(1)(sillyButValidHash).add(2).iterator.toList
res2: Boolean = true I personally would never want this to be intended behavior, as if I have more than one instance of I was under the impression that binding the instance at the method or at the class was mostly for convenience (and preventing damage to internal state of an already allocated structure) and not as a mechanism for using alternative instances. I would expect to use newtypes (ideally opaque types) to index alternative implementations. |
The problem is if you take the instance at the call site then you can do this: HashSet(1).add(2)(sillyButValidHash) Which is also bad. Oscar just summarized this nicely in #277 (comment).
|
👍 yes, this is the only safe way. |
👍 You scared me for a minute. So coming back to My intended strategy would probably be to introduce a new class Thoughts? |
Sure, maybe |
@isomarcte I think there are two strategies possible:
Also as I mentioned above, I personally would find useful to have All above is my personal perception of course. |
Thanks for that distinction, at least for me I think that helped clarify things. I think (1) is an "interval": it is a set of things, in some natural order. Whereas (2) is a "range" since you are not only specifying the set, but in which order to iterate it. I am not sure if that means we have to reverse the |
In theory yes, it should not be the property of Range. But the way it is currently implemented is that |
@satorg RE 1.CONS Assuming the inclusion of val a: Interval[Int] = Interval(1, 10)
val b: Interval[Inverse[Int]] = a.reverse
def reverse: Interval[Inverse[A]] =
Interval(Inverse(end), Inverse(start))
def contains(value: Interval[A]): Boolean = ???
def containsInverse(value: Interval[Inverse[A]]): Boolean =
contains(value.reverse)
// Just a rough sketch. I might be able to do something interesting so that
// (a: Interval[Inverse[A]]).reverse => Interval[A], and not
// Interval[Inverse[Inverse[A]]]
:t reverse
Interval[A] => Interval[Inverse[A]]
:t contains
Interval[A] => Interval[A] => Boolean
:t containsInverse
Interval[A] => Interval[Inverse[A]] => Boolean And I'm completely fine making it exclusive on the upper bound. I think that would even be required, since if we require that |
I can also just make a POC PR as well, if that would be easier for discussion. |
Yes, I think it makes sense as an option... But on the other hand.... Imagine that we need to make Another (but similar) example: sealed trait MyNum
object MyNum {
object One extends MyNum
object Two extends MyNum
object Three extends MyNum
object Four extends MyNum
} Apparently we can define some |
As a bottomline: there's a controverity: if This is why I think it should allow both options. |
On the second thought... Perhaps, the idea is too drastic, but... is there really a necessity for having classes like |
@satorg I would say yes. An Having a base type with the correct semantics to implement these is, I think, quite useful. I am of course heavily biased here. I started down this path because a nice |
I basically agree. But what I am thinking about (and yeah, perhaps it is too crazy) is to make class Diet[A, R] {} where |
I've noticed some inconsistencies with how several methods on
Range
and that useRange
are defined when dealing with ranges which go different directions.Range.contains
contains
forRange
is not symmetric aroundreverse
.Perhaps most troubling,
This is made more confusing when looking at how
Range
is used withDiet
.There are a few ways to remedy this that come to mind, though I think the most simple would be to change
Range
to be defined as always going in one direction. If aRange
is desired that is going in the inverse order, then an newtype (perhaps Inverse) could be used.The text was updated successfully, but these errors were encountered: