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

Semigroup for NonEmptyMap is kind of weird #3377

Closed
travisbrown opened this issue Apr 1, 2020 · 4 comments · Fixed by #3380 or #3807
Closed

Semigroup for NonEmptyMap is kind of weird #3377

travisbrown opened this issue Apr 1, 2020 · 4 comments · Fixed by #3380 or #3807

Comments

@travisbrown
Copy link
Contributor

In any recent Cats version (back to before 2.0) |+| is ++ for non-empty maps:

scala> import cats.data.NonEmptyMap, cats.implicits._
import cats.data.NonEmptyMap
import cats.implicits._

scala> NonEmptyMap.of("a" -> List(1)) |+| NonEmptyMap.of("a" -> List(2))
res0: cats.data.NonEmptyMap[String,List[Int]] = Map(a -> List(2))

I don't really use NonEmptyMap, so maybe I'm missing something, but this seems like the wrong thing to do, since |+| for other maps combines at the element level:

scala> Map("a" -> List(1)) |+| Map("a" -> List(2))
res1: scala.collection.immutable.Map[String,List[Int]] = Map(a -> List(1, 2))

We can fix this but it'll take some fussing with, since we'll have to make the current Band instance non-implicit, add some new prioritized instances, etc.

@travisbrown
Copy link
Contributor Author

@djspiewak This issue is actually unrelated to #3380, although I ran into it when I was looking into the other issue (which had to do with Map, not NonEmptyMap, which the problem here is specific to).

@travisbrown travisbrown reopened this Apr 6, 2020
@joroKr21
Copy link
Member

I guess this would mean deprecating Band for NonEmptyMap because otherwise it would take priority. Which should be fine because SortedMap doesn't have a Band instance.

On the other hand seems to me that resolving #3223 first would be good.

@brunoatArgos
Copy link

Hi @travisbrown, I had to face this issue and I resolved locally adding the following implicit:

  implicit def replaceCatsDataBandForNonEmptyMap[K: Order, V: Semigroup]: Band[NonEmptyMap[K, V]] =
    (x: NonEmptyMap[K, V], y: NonEmptyMap[K, V]) =>
      NonEmptyMap.fromMapUnsafe(x.toSortedMap combine y.toSortedMap)

to be used instead of the current implementation that uses concat for combine

implicit def catsDataBandForNonEmptyMap[K, A]: Band[NonEmptyMap[K, A]] = new Band[NonEmptyMap[K, A]] {
def combine(x: NonEmptyMap[K, A], y: NonEmptyMap[K, A]): NonEmptyMap[K, A] = x ++ y
}

@nigredo-tori
Copy link
Contributor

I've just hit this as well... I'm used to the "deep combine" behavior for SortedMap, and the destructive behavior for NonEmptyMap came as a shock. Thankfully, I happened to catch this before it led to any issues - but It's easy to miss a Semigroup instance where there shouldn't be one. I feel like this has a potential to introduce a lot of subtle errors.

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