Skip to content

Commit de0056b

Browse files
authored
Backports for a cats-1.6.x patch (#2861)
* Change MonadErrorOps#reject so it no longer runs effects twice (#2810) * Add regression test for MonadErrorOps bug * Change MonadErrorOps#reject so it no longer re-runs the effect it is called on. Fixes #2809 * Fix Order.max and Oder.min description comments (#2842) Changed description to better fit their implentation * Make WrappedMutableMapBase extend Serializable (#2784) We are running into Spark `Task not serializable` issues when a closure that executes on a Spark executor node involves a `Map` that is created via running `foldMap` on a `List`. This commit makes the `WrappedMutableMap` hierarchy extend `Serializable` and chex that the cerealization works (this test failed before extending `Serializable`). * Optimize productR in Apply (#2728)
1 parent 64b83d0 commit de0056b

7 files changed

Lines changed: 17 additions & 7 deletions

File tree

core/src/main/scala/cats/Apply.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ trait Apply[F[_]] extends Functor[F] with InvariantSemigroupal[F] with ApplyArit
7272
*
7373
*/
7474
def productR[A, B](fa: F[A])(fb: F[B]): F[B] =
75-
map2(fa, fb)((_, b) => b)
75+
ap(map(fa)(_ => (b: B) => b))(fb)
7676

7777
/**
7878
* Compose two actions, discarding any value produced by the second.

core/src/main/scala/cats/syntax/monadError.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ final class MonadErrorOps[F[_], E, A](private val fa: F[A]) extends AnyVal {
2424
*/
2525
def reject(pf: PartialFunction[A, E])(implicit F: MonadError[F, E]): F[A] =
2626
F.flatMap(fa) { a =>
27-
pf.andThen(F.raiseError[A]).applyOrElse(a, (_: A) => fa)
27+
pf.andThen(F.raiseError[A] _).applyOrElse(a, F.pure)
2828
}
2929

3030
def adaptError(pf: PartialFunction[E, E])(implicit F: MonadError[F, E]): F[A] =

kernel/src/main/scala-2.12-/cats/kernel/compat/WrappedMutableMapBase.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package compat
33

44
import scala.collection.mutable
55

6-
abstract private[kernel] class WrappedMutableMapBase[K, V](m: mutable.Map[K, V]) extends Map[K, V] {
6+
abstract private[kernel] class WrappedMutableMapBase[K, V](m: mutable.Map[K, V]) extends Map[K, V] with Serializable {
77
def +[V2 >: V](kv: (K, V2)): Map[K, V2] = m.toMap + kv
88
def -(key: K): Map[K, V] = m.toMap - key
99
}

kernel/src/main/scala-2.13+/cats/kernel/compat/WrappedMutableMapBase.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package compat
33

44
import scala.collection.mutable
55

6-
abstract private[kernel] class WrappedMutableMapBase[K, V](m: mutable.Map[K, V]) extends Map[K, V] {
6+
abstract private[kernel] class WrappedMutableMapBase[K, V](m: mutable.Map[K, V]) extends Map[K, V] with Serializable {
77
def updated[V2 >: V](key: K, value: V2): Map[K, V2] = m.toMap + ((key, value))
88
def remove(key: K): Map[K, V] = m.toMap - key
99
}

kernel/src/main/scala/cats/kernel/Order.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@ trait Order[@sp A] extends Any with PartialOrder[A] { self =>
3838
def partialCompare(x: A, y: A): Double = compare(x, y).toDouble
3939

4040
/**
41-
* If x <= y, return x, else return y.
41+
* If x < y, return x, else return y.
4242
*/
4343
def min(x: A, y: A): A = if (lt(x, y)) x else y
4444

4545
/**
46-
* If x >= y, return x, else return y.
46+
* If x > y, return x, else return y.
4747
*/
4848
def max(x: A, y: A): A = if (gt(x, y)) x else y
4949

tests/src/test/scala/cats/tests/MapSuite.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import cats.laws.discipline.{
1111
}
1212
import cats.laws.discipline.arbitrary._
1313
import cats.arrow.Compose
14+
import cats.kernel.instances.StaticMethods.wrapMutableMap
1415

1516
class MapSuite extends CatsSuite {
1617
implicit val iso = SemigroupalTests.Isomorphisms.invariant[Map[Int, ?]]
@@ -38,4 +39,9 @@ class MapSuite extends CatsSuite {
3839
map.show should ===(implicitly[Show[Map[Int, String]]].show(map))
3940
}
4041
}
42+
43+
{
44+
val m = wrapMutableMap(scala.collection.mutable.Map(1 -> "one", 2 -> "two"))
45+
checkAll("WrappedMutableMap", SerializableTests.serializable(m))
46+
}
4147
}

tests/src/test/scala/cats/tests/RegressionSuite.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package cats
22
package tests
33

4-
import cats.data.{Const, NonEmptyList}
4+
import cats.data.{Const, NonEmptyList, StateT}
55
import scala.collection.mutable
66
import scala.collection.immutable.SortedMap
77
class RegressionSuite extends CatsSuite {
@@ -157,4 +157,8 @@ class RegressionSuite extends CatsSuite {
157157

158158
}
159159

160+
test("#2809 MonadErrorOps.reject runs effects only once") {
161+
val program = StateT.modify[Either[Throwable, ?], Int](_ + 1).reject { case _ if false => new Throwable }
162+
program.runS(0).right.get should ===(1)
163+
}
160164
}

0 commit comments

Comments
 (0)