From 732d4d50f21b6d391b0031e86e84920ec511518b Mon Sep 17 00:00:00 2001 From: Edmund Noble Date: Thu, 4 May 2017 23:00:29 -0400 Subject: [PATCH] Make Show contravariant without breaking things --- core/src/main/scala/cats/Show.scala | 9 ++++++-- .../src/test/scala/cats/tests/ShowTests.scala | 23 ++++++++++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/core/src/main/scala/cats/Show.scala b/core/src/main/scala/cats/Show.scala index 3f32bdb9967..590a49f8364 100644 --- a/core/src/main/scala/cats/Show.scala +++ b/core/src/main/scala/cats/Show.scala @@ -10,11 +10,16 @@ import cats.functor.Contravariant * made a toString method, a Show instance will only exist if someone * explicitly provided one. */ -@typeclass trait Show[T] { +@typeclass trait Show[T] extends Show.ContravariantShow[T] { + // duplicated so simulacrum knows it requires an instance of this trait def show(t: T): String } object Show { + trait ContravariantShow[-T] { + def show(t: T): String + } + /** creates an instance of [[Show]] using the provided function */ def show[A](f: A => String): Show[A] = new Show[A] { def show(a: A): String = f(a) @@ -27,7 +32,7 @@ object Show { final case class Shown(override val toString: String) extends AnyVal object Shown { - implicit def mat[A](x: A)(implicit z: Show[A]): Shown = Shown(z show x) + implicit def mat[A](x: A)(implicit z: ContravariantShow[A]): Shown = Shown(z show x) } final case class ShowInterpolator(_sc: StringContext) extends AnyVal { diff --git a/tests/src/test/scala/cats/tests/ShowTests.scala b/tests/src/test/scala/cats/tests/ShowTests.scala index 5f3cb31477a..d021540cb8f 100644 --- a/tests/src/test/scala/cats/tests/ShowTests.scala +++ b/tests/src/test/scala/cats/tests/ShowTests.scala @@ -11,7 +11,6 @@ class ShowTests extends CatsSuite { checkAll("Contravariant[Show]", SerializableTests.serializable(Contravariant[Show])) test("show string interpolator") { - import cats.syntax.show._ case class Cat(name: String) object Cat { @@ -31,4 +30,26 @@ class ShowTests extends CatsSuite { assertResult("Good morning, Whiskers!")(show"Good $tod, ${List(cat).head}!") } + + test("show string interpolator and contravariance") { + + case class Cat(name: String) + object Cat { + implicit val showCat: Show[Cat] = Show.show(_.name) + } + + sealed trait TimeOfDay + case object Morning extends TimeOfDay + object TimeOfDay { + implicit val showTimeOfDay: Show[TimeOfDay] = Show.show { case Morning => "morning" } + } + + // only difference: no type annotation here + val tod = Morning + val cat = Cat("Whiskers") + + assertResult("Good morning, Whiskers!")(show"Good $tod, $cat!") + + assertResult("Good morning, Whiskers!")(show"Good $tod, ${List(cat).head}!") + } }