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

Make Show inherit from a contravariant base trait #1649

Merged
merged 1 commit into from
Jul 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we can get the test to pass by asking for Show[_ >: A] which is effectively what this trick is doing, and not having to introduce the new type. I think we can (at least on 2.12).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately type inference looks to be just slightly shy, like it was when I asked for [A, B >: A](x: A)(implicit z: Show[B]): it never converts anything to a Shown.

[error] /Users/edmund/workspace/scala/cats/tests/src/test/scala/cats/tests/ShowTests.scala:29: type mismatch;
[error]  found   : TimeOfDay
[error]  required: cats.Show.Shown
[error]     assertResult("Good morning, Whiskers!")(show"Good $tod, $cat!")
[error]                                                        ^
[error] /Users/edmund/workspace/scala/cats/tests/src/test/scala/cats/tests/ShowTests.scala:29: type mismatch;
[error]  found   : Cat
[error]  required: cats.Show.Shown
[error]     assertResult("Good morning, Whiskers!")(show"Good $tod, $cat!")
[error]                                                              ^
[error] /Users/edmund/workspace/scala/cats/tests/src/test/scala/cats/tests/ShowTests.scala:31: type mismatch;
[error]  found   : TimeOfDay
[error]  required: cats.Show.Shown
[error]     assertResult("Good morning, Whiskers!")(show"Good $tod, ${List(cat).head}!")
[error]                                                        ^
[error] /Users/edmund/workspace/scala/cats/tests/src/test/scala/cats/tests/ShowTests.scala:31: type mismatch;
[error]  found   : Cat
[error]  required: cats.Show.Shown
[error]     assertResult("Good morning, Whiskers!")(show"Good $tod, ${List(cat).head}!")
[error]                                                                         ^
[error] /Users/edmund/workspace/scala/cats/tests/src/test/scala/cats/tests/ShowTests.scala:46: type mismatch;
[error]  found   : Cat
[error]  required: cats.Show.Shown
[error]     assertResult("Good morning, Whiskers!")(show"Good morning, $cat!")
[error]                                                                 ^
[error] 5 errors found

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when I did a simple test in the repl this worked when I did implicitly[Foo[_ >: A]] did you try that form (not putting a specific type)? you never know with scala which minor translation of the code will work.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An implicit in the repl is like you've imported it. His is in the Shown companion object.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right. That clarifies it for me.

}

final case class ShowInterpolator(_sc: StringContext) extends AnyVal {
Expand Down
19 changes: 12 additions & 7 deletions tests/src/test/scala/cats/tests/ShowTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,28 @@ class ShowTests extends CatsSuite {
checkAll("Contravariant[Show]", ContravariantTests[Show].contravariant[Int, Int, Int])
checkAll("Contravariant[Show]", SerializableTests.serializable(Contravariant[Show]))

sealed trait TimeOfDay
case object Morning extends TimeOfDay
object TimeOfDay {
implicit val showTimeOfDay: Show[TimeOfDay] = Show.show { case Morning => "morning" }
}

test("show string interpolator") {
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" }
}

val tod: TimeOfDay = Morning
val cat = Cat("Whiskers")

assertResult("Good morning, Whiskers!")(show"Good $tod, $cat!")

assertResult("Good morning, Whiskers!")(show"Good $tod, ${List(cat).head}!")
}

test("show string interpolator and contravariance") {
val tod: Morning.type = Morning

assertResult("Good morning")(show"Good $tod")
}
}