Skip to content

Commit

Permalink
Make Show contravariant without breaking things
Browse files Browse the repository at this point in the history
  • Loading branch information
edmundnoble committed Jun 28, 2017
1 parent bbc97b8 commit 732d4d5
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 3 deletions.
9 changes: 7 additions & 2 deletions core/src/main/scala/cats/Show.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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 {
Expand Down
23 changes: 22 additions & 1 deletion tests/src/test/scala/cats/tests/ShowTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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}!")
}
}

0 comments on commit 732d4d5

Please sign in to comment.