From 5a0ef403dd0da8ff7021df6448d91580fb7ead0f Mon Sep 17 00:00:00 2001 From: Cody Allen Date: Thu, 28 May 2020 16:28:25 -0700 Subject: [PATCH] Make boilerplate syntax classes extend Serializable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Today I ran into a serializability issue when using `mapN` in a Spark environment 😬. --- .../main/scala/cats/syntax/semigroupal.scala | 2 +- project/Boilerplate.scala | 8 +++--- .../cats/tests/SyntaxSerializationSuite.scala | 25 +++++++++++++++++++ 3 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 tests/src/test/scala/cats/tests/SyntaxSerializationSuite.scala diff --git a/core/src/main/scala/cats/syntax/semigroupal.scala b/core/src/main/scala/cats/syntax/semigroupal.scala index 13786bb911..dac0b4e440 100644 --- a/core/src/main/scala/cats/syntax/semigroupal.scala +++ b/core/src/main/scala/cats/syntax/semigroupal.scala @@ -11,7 +11,7 @@ trait SemigroupalSyntax { } } -abstract class SemigroupalOps[F[_], A] extends Semigroupal.Ops[F, A] { +abstract class SemigroupalOps[F[_], A] extends Semigroupal.Ops[F, A] with Serializable { @deprecated("Replaced by an apply syntax, e.g. instead of (a |@| b).map(...) use (a, b).mapN(...)", "1.0.0-MF") final private[syntax] def |@|[B](fb: F[B]): SemigroupalBuilder[F]#SemigroupalBuilder2[A, B] = diff --git a/project/Boilerplate.scala b/project/Boilerplate.scala index 72447bdef5..742a33a94d 100644 --- a/project/Boilerplate.scala +++ b/project/Boilerplate.scala @@ -149,10 +149,10 @@ object Boilerplate { | | |@deprecated("replaced by apply syntax", "1.0.0-MF") - |private[syntax] final class SemigroupalBuilder[F[_]] { + |private[syntax] final class SemigroupalBuilder[F[_]] extends Serializable { | def |@|[A](a: F[A]) = new SemigroupalBuilder1(a) | - - private[syntax] final class SemigroupalBuilder$arity[${`A..N`}]($params) { + - private[syntax] final class SemigroupalBuilder$arity[${`A..N`}]($params) extends Serializable { - $next - def apWith[Z](f: F[(${`A..N`}) => Z])(implicit apply: Apply[F]): F[Z] = apply.ap$n(f)(${`a..n`}) - $map @@ -417,7 +417,7 @@ object Boilerplate { - implicit def catsSyntaxTuple${arity}Parallel[M[_], ${`A..N`}]($tupleTpe): Tuple${arity}ParallelOps[M, ${`A..N`}] = new Tuple${arity}ParallelOps(t$arity) |} | - -private[syntax] final class Tuple${arity}ParallelOps[M[_], ${`A..N`}](private val $tupleTpe) { + -private[syntax] final class Tuple${arity}ParallelOps[M[_], ${`A..N`}](private val $tupleTpe) extends Serializable { - $parMap - $parTupled -} @@ -487,7 +487,7 @@ object Boilerplate { - implicit def catsSyntaxTuple${arity}Semigroupal[F[_], ${`A..N`}]($tupleTpe): Tuple${arity}SemigroupalOps[F, ${`A..N`}] = new Tuple${arity}SemigroupalOps(t$arity) |} | - -private[syntax] final class Tuple${arity}SemigroupalOps[F[_], ${`A..N`}](private val $tupleTpe) { + -private[syntax] final class Tuple${arity}SemigroupalOps[F[_], ${`A..N`}](private val $tupleTpe) extends Serializable { - $map - $contramap - $imap diff --git a/tests/src/test/scala/cats/tests/SyntaxSerializationSuite.scala b/tests/src/test/scala/cats/tests/SyntaxSerializationSuite.scala new file mode 100644 index 0000000000..dad0d7a95d --- /dev/null +++ b/tests/src/test/scala/cats/tests/SyntaxSerializationSuite.scala @@ -0,0 +1,25 @@ +package cats.tests + +import cats.laws.discipline.SerializableTests + +/** + * Test that our syntax implicits are serializable. + */ +class SyntaxSerializationSuite extends CatsSuite { + checkAll( + "Tuple3SemigroupalOps[Option, Boolean, Int, Long]", + SerializableTests.serializable( + cats.syntax.all.catsSyntaxTuple3Semigroupal[Option, Boolean, Int, Long]((None, None, None)) + ) + ) + + checkAll("SemigroupalOps[Option, Int]", + SerializableTests.serializable(cats.syntax.all.catsSyntaxSemigroupal[Option, Int](None))) + + checkAll( + "Tuple3ParallelOps[Either[String, ?], Boolean, Int, Long]", + SerializableTests.serializable( + cats.syntax.all.catsSyntaxTuple3Parallel[Either[String, ?], Boolean, Int, Long]((Left("a"), Left("b"), Left("c"))) + ) + ) +}