Eq[Set[A]] instance is not lawful
Nobody has claimed this yet.
- Dominant language
- Scala
- Stars
- 5.5k
- Forks
- 1.2k
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 5
Description
The Eq[Set[A]] instance given here is not lawful. It doesn't satisfy the substitution property given here that says
- ∀ a, b, f:
- a=b ⇒ f(a)=f(b)
The problem is that Sets expose some intrinsic order of elements (observable via methods like iterator, foldLeft, ...). For some implementations of sets, e.g. ListSet and HashSet, it is possible to construct two instances that contain the same elements (and are thus considered equal by the provided Eq), but iterate over them in different order (so it is possible to define a function f that falsifies the substitution property above). As a result, the provided Eq instance is not equality, just equivalence.
I'm not sure what should be done about it, if anything. It would be easy to declare Set from stdlib broken, but how would we handle the issue with an idealized implementation of Set?
Some possibilities are:
-
Have a type class
Equivfor equivalence (thenEq extends Equiv) and only provideEquiv[Set], notEq[Set]. (We might then also need another typeclass for order which represents order on the equivalence classes.) -
Our idealized
Setwould not have any API that exposes the intrinsic order. This means, for example, that we lose theFoldable[Set]instance, since folds expose order of elements. We could, however, have for examplefoldMapwith an additional constraint that the monoid be commutative:def foldMap[A, B](fa: Set[A])(f: A => B)(implicit B: CommutativeMonoid[B]): BThen the order would remain unobservable. Is there something like
CommutativeFoldable?
Another issue is that this problem is not caught by current tests, since ScalaCheck will never (IMO) generate a function f: Set[A] => Set[A] whose return value depends on the intrinsic order of the argument. As currently written, OrderLaws do not let me pass in my own Arbitrary[A => A].
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read kernel/src/main/scala/cats/kernel/instances/set.scala and kernel-laws/src/main/scala/cats/kernel/laws/OrderLaws.scala first. Investigate the substitution-property concern for Set instances and the limitation around Arbitrary function generation. Done requires a decided approach and corresponding instance or law-test changes, but the issue does not specify which option to adopt.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- scala
- Domain
- backend-api-design, testing-qa
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100