Skip to content
10 changes: 2 additions & 8 deletions core/src/main/scala/cats/Show.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,12 @@ object Show extends ScalaVersionSpecificShowInstances with ShowInstances {
/**
* 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)
}
def show[A](f: A => String): Show[A] = f(_)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is there a practical difference between these? e.g. no class is emitted.

Copy link
Copy Markdown
Member Author

@joroKr21 joroKr21 Feb 10, 2022

Choose a reason for hiding this comment

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

Yes, indeed 👍 - because Show has only one abstract method

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Right, thanks. Is this affected by the aforementioned Scala 2 bug?

Also, can Semigroup etc. get the same treatment?

@inline def instance[A](cmb: (A, A) => A): Semigroup[A] =
new Semigroup[A] {
override def combine(x: A, y: A): A = cmb(x, y)
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I think for Semigroup it doesn't matter because it has other (non-abstract) methods. So then the bug applies and there would be an anonymous classes generated even if we use the SAM syntax. So the only benefit would be aesthetics.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I see, so it's not just that Show has one abstract method, it's that it has no other methods.

I agree it's only aesthetics on Scala 2, but does the bug apply to Scala 3 as well?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I agree it's only aesthetics on Scala 2, but does the bug apply to Scala 3 as well?

I don't remember - that's a good question.

Copy link
Copy Markdown
Member

@armanbilge armanbilge Feb 10, 2022

Choose a reason for hiding this comment

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

The reason I ask is, I don't care so much about the handful of Semigroup.instance etc. that can be re-written.

But I'm wondering if in Scala 3 the boilerplate instances themselves could be written directly like this instead of relying on instance. So we get the win in terms of jar size without introducing any indirection at all.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Even if that's possible it would be quite hard to split like this 😄

Copy link
Copy Markdown
Member Author

@joroKr21 joroKr21 Feb 10, 2022

Choose a reason for hiding this comment

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

FTR Scala 3 doesn't have this bug - but again I'm sceptical about version-specific boilerplate generators 🤔

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If there's interest it can be a followup PR. I think it shouldn't be too hard (famous last words): currently all the instances are in the same file I think, when they could easily be split among a few files. And some of those files can go into the scala-2 and scala-3 srcs.


/**
* creates an instance of [[Show]] using object toString
*/
def fromToString[A]: Show[A] =
new Show[A] {
def show(a: A): String = a.toString
}
def fromToString[A]: Show[A] = _.toString

final case class Shown(override val toString: String) extends AnyVal
object Shown {
Expand Down
5 changes: 1 addition & 4 deletions kernel/src/main/scala/cats/kernel/Hash.scala
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,9 @@ object Hash extends HashFunctions[Hash] {
def hash(x: A) = x.hashCode()
def eqv(x: A, y: A) = x == y
}

}

trait HashToHashingConversion {
implicit def catsKernelHashToHashing[A](implicit ev: Hash[A]): Hashing[A] =
new Hashing[A] {
override def hash(x: A): Int = ev.hash(x)
}
ev.hash(_)
}
44 changes: 21 additions & 23 deletions project/AlgebraBoilerplate.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,7 @@ object AlgebraBoilerplate {
val synVals = (0 until arity).map(n => s"a$n")
val `A..N` = synTypes.mkString(", ")
val `a..n` = synVals.mkString(", ")
val `_.._` = Seq.fill(arity)("_").mkString(", ")
val `(A..N)` = if (arity == 1) "Tuple1[A0]" else synTypes.mkString("(", ", ", ")")
val `(_.._)` = if (arity == 1) "Tuple1[_]" else Seq.fill(arity)("_").mkString("(", ", ", ")")
val `(a..n)` = if (arity == 1) "Tuple1(a)" else synVals.mkString("(", ", ", ")")
}

Expand Down Expand Up @@ -86,32 +84,32 @@ object AlgebraBoilerplate {
import tv._

def constraints(constraint: String) =
synTypes.map(tpe => s"${tpe}: ${constraint}[${tpe}]").mkString(", ")
synTypes.map(tpe => s"$tpe: $constraint[$tpe]").mkString(", ")

def tuple(results: TraversableOnce[String]) = {
val resultsVec = results.toVector
val a = synTypes.size
val r = s"${0.until(a).map(i => resultsVec(i)).mkString(", ")}"
if (a == 1) "Tuple1(" ++ r ++ ")"
else s"(${r})"
else s"($r)"
}

def binMethod(name: String) =
synTypes.zipWithIndex.iterator.map { case (tpe, i) =>
val j = i + 1
s"${tpe}.${name}(x._${j}, y._${j})"
s"$tpe.$name(x._$j, y._$j)"
}

def binTuple(name: String) =
tuple(binMethod(name))

def unaryTuple(name: String) = {
val m = synTypes.zipWithIndex.map { case (tpe, i) => s"${tpe}.${name}(x._${i + 1})" }
val m = synTypes.zipWithIndex.map { case (tpe, i) => s"$tpe.$name(x._${i + 1})" }
tuple(m)
}

def nullaryTuple(name: String) = {
val m = synTypes.map(tpe => s"${tpe}.${name}")
val m = synTypes.map(tpe => s"$tpe.$name")
tuple(m)
}

Expand All @@ -125,34 +123,34 @@ object AlgebraBoilerplate {
-
- implicit def tuple${arity}Rig[${`A..N`}](implicit ${constraints("Rig")}): Rig[${`(A..N)`}] =
- new Rig[${`(A..N)`}] {
- def one: ${`(A..N)`} = ${nullaryTuple("one")}
- def plus(x: ${`(A..N)`}, y: ${`(A..N)`}): ${`(A..N)`} = ${binTuple("plus")}
- def times(x: ${`(A..N)`}, y: ${`(A..N)`}): ${`(A..N)`} = ${binTuple("times")}
- def zero: ${`(A..N)`} = ${nullaryTuple("zero")}
- def zero = ${nullaryTuple("zero")}
- def one = ${nullaryTuple("one")}
- def plus(x: ${`(A..N)`}, y: ${`(A..N)`}) = ${binTuple("plus")}
- def times(x: ${`(A..N)`}, y: ${`(A..N)`}) = ${binTuple("times")}
- }
-
- implicit def tuple${arity}Ring[${`A..N`}](implicit ${constraints("Ring")}): Ring[${`(A..N)`}] =
- new Ring[${`(A..N)`}] {
- def one: ${`(A..N)`} = ${nullaryTuple("one")}
- def plus(x: ${`(A..N)`}, y: ${`(A..N)`}): ${`(A..N)`} = ${binTuple("plus")}
- def times(x: ${`(A..N)`}, y: ${`(A..N)`}): ${`(A..N)`} = ${binTuple("times")}
- def zero: ${`(A..N)`} = ${nullaryTuple("zero")}
- def negate(x: ${`(A..N)`}): ${`(A..N)`} = ${unaryTuple("negate")}
- def zero = ${nullaryTuple("zero")}
- def one = ${nullaryTuple("one")}
- def negate(x: ${`(A..N)`}) = ${unaryTuple("negate")}
- def plus(x: ${`(A..N)`}, y: ${`(A..N)`}) = ${binTuple("plus")}
- def times(x: ${`(A..N)`}, y: ${`(A..N)`}) = ${binTuple("times")}
- }
-
- implicit def tuple${arity}Rng[${`A..N`}](implicit ${constraints("Rng")}): Rng[${`(A..N)`}] =
- new Rng[${`(A..N)`}] {
- def plus(x: ${`(A..N)`}, y: ${`(A..N)`}): ${`(A..N)`} = ${binTuple("plus")}
- def times(x: ${`(A..N)`}, y: ${`(A..N)`}): ${`(A..N)`} = ${binTuple("times")}
- def zero: ${`(A..N)`} = ${nullaryTuple("zero")}
- def negate(x: ${`(A..N)`}): ${`(A..N)`} = ${unaryTuple("negate")}
- def zero = ${nullaryTuple("zero")}
- def negate(x: ${`(A..N)`}) = ${unaryTuple("negate")}
- def plus(x: ${`(A..N)`}, y: ${`(A..N)`}) = ${binTuple("plus")}
- def times(x: ${`(A..N)`}, y: ${`(A..N)`}) = ${binTuple("times")}
- }
-
- implicit def tuple${arity}Semiring[${`A..N`}](implicit ${constraints("Semiring")}): Semiring[${`(A..N)`}] =
- new Semiring[${`(A..N)`}] {
- def plus(x: ${`(A..N)`}, y: ${`(A..N)`}): ${`(A..N)`} = ${binTuple("plus")}
- def times(x: ${`(A..N)`}, y: ${`(A..N)`}): ${`(A..N)`} = ${binTuple("times")}
- def zero: ${`(A..N)`} = ${nullaryTuple("zero")}
- def zero = ${nullaryTuple("zero")}
- def plus(x: ${`(A..N)`}, y: ${`(A..N)`}) = ${binTuple("plus")}
- def times(x: ${`(A..N)`}, y: ${`(A..N)`}) = ${binTuple("times")}
- }
|}
"""
Expand Down
16 changes: 4 additions & 12 deletions project/Boilerplate.scala
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,6 @@ object Boilerplate {
if (arity <= 2) "(*, *)"
else `A..(N - 2)`.mkString("(", ", ", ", *, *)")
val `a..(n - 1)` = (0 until (arity - 1)).map(n => s"a$n")
val `fa._1..fa._(n - 2)` =
if (arity <= 2) "" else (0 until (arity - 2)).map(n => s"fa._${n + 1}").mkString("", ", ", ", ")
val `pure(fa._1..(n - 2))` =
if (arity <= 2) "" else (0 until (arity - 2)).map(n => s"G.pure(fa._${n + 1})").mkString("", ", ", ", ")
val `a0, a(n - 1)` = if (arity <= 1) "" else `a..(n - 1)`.mkString(", ")
val `[A0, A(N - 1)]` = if (arity <= 1) "" else `A..(N - 1)`.mkString("[", ", ", "]")
val `(A0, A(N - 1))` =
Expand All @@ -87,19 +83,15 @@ object Boilerplate {
val `(A..N - 1, *)` =
if (arity == 1) "Tuple1"
else `A..(N - 1)`.mkString("(", ", ", ", *)")
val `(fa._1..(n - 1))` =
if (arity <= 1) "Tuple1.apply" else (0 until (arity - 1)).map(n => s"fa._${n + 1}").mkString("(", ", ", ", _)")

def `A0, A(N - 1)&`(a: String): String =
if (arity <= 1) s"Tuple1[$a]" else `A..(N - 1)`.mkString("(", ", ", s", $a)")

def `fa._1..(n - 1) & `(a: String): String =
if (arity <= 1) s"Tuple1($a)" else (0 until (arity - 1)).map(n => s"fa._${n + 1}").mkString("(", ", ", s", $a)")

def `constraints A..N`(c: String): String = synTypes.map(tpe => s"$tpe: $c[$tpe]").mkString("(implicit ", ", ", ")")
def `constraints A..N`(c: String): String =
synTypes.map(tpe => s"$tpe: $c[$tpe]").mkString("(implicit ", ", ", ")")
def `constraints A..(N-1)`(c: String): String =
if (arity <= 1) "" else `A..(N - 1)`.map(tpe => s"$tpe: $c[$tpe]").mkString("(implicit ", ", ", ")")
def `parameters A..(N-1)`(c: String): String = `A..(N - 1)`.map(tpe => s"$tpe: $c[$tpe]").mkString(", ")
def `parameters A..(N-1)`(c: String): String =
`A..(N - 1)`.map(tpe => s"$tpe: $c[$tpe]").mkString(", ")
}

trait Template {
Expand Down
Loading