Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Heap bugs with Order #1236
(I don't think this is likely to be a new issue, but I couldn't find any previous issues that discussed it.)
import scalaz._ import Scalaz._ def revOrd: Order[Int] = implicitly[Order[Int]].reverseOrder val h = Heap.singleton(5).insert(7) val h2 = h.insert(4)(revOrd) println(h2.minimum) // prints 5!
Of course, a programmer that does this deliberately may deserve what they get, but, because of implicits, this could easily happen accidentally when somebody creates a heap in one scope and inserts into it in a different scope that has a different implicit order defined..
Similar issues occur with the other insert methods, as well as with
This bug is almost certainly because the code was ported from Haskell, where a given type can only have a single
I've written a description of one approach to fixing the API of heaps to avoid this issue:
That's true, but we deliberately make the simplifying assumption that you will define typeclass instances in a globally coherent way, and use
@chrisokasaki I raised a similar issue some time ago (#671), just for some historical context. Because of the broadly coherence-dependent assumptions that surround the scalaz API, I doubt this is a line of research that would be considered useful for the library.
Regarding your proposal document:
@djspiewak Thanks. I was unaware of the Bill Venners video until somebody else pointed me to it earlier today. He is certainly doing similar things and is farther along in the process as well!
I happened to be at a meeting with Martin two weeks ago, and he encouraged me to flesh out a proposal for heaps.
Some folks have found my previous comment unwelcoming or rude to @chrisokasaki, or think that I've been overly dismissive of an absolutely accurate concern. I understand that; I relied on lots of implicit assumptions and context about Scalaz that haven't really been written down, and you couldn't be expected to know without spending a lot of time in the community, more time than many have available. So I thought I would expand on @djspiewak's point, which is an accurate summary:
In Scalaz, we think that global typeclass coherence is very important for usability and refactorability when employing "the typeclass pattern", whether by defining your own classes, instances, or just using the classes+instances defined by Scalaz. I want to highlight the "refactorability" concern specifically, because we aren't always the best at choosing the right place to place constraints, or applying the correct constraints to the instances we provide, so they sometimes move around from release to release.
With coherence, our users can be assured that our changes here will not silently break working code; if anything, they will manifest as a compiler error where additional constraints are required.
Of course, this comes at the cost of both carefully following the coherence rules ourselves, and demanding that our users follow these rules, too. For example, we ask users who wish to define incompatible instances (i.e. alternative "coherence domains") to combine global coherence with
In my experience, and I suspect that of many other Scalaz users, the usability and refactorability benefits well exceed these costs.
Among the conveniences we can provide to users because of this shared covenant of coherence is that the interface for
However, in Scalaz, we have already charged users with preserving coherence, though; in this, they have already paid for consistently-structured mergeable heaps et al, and it would be a needless usability barrier to charge them more.
I should emphasize again, I agree 100% with the point that nonsense will happen if you do not have global coherence, e.g. you have "a different scope that has a different implicit order defined". We don't have a means in Scala to enforce global coherence², so these things can potentially happen. Nevertheless, the practical API usability and implementation advantages of assuming coherence seem to outweigh by quite a lot the danger of failing to account for incoherent instances, in my experience.