Deriving typeclass instances for generic classes #14291
Unanswered
adamw
asked this question in
Metaprogramming
Replies: 1 comment 3 replies
-
The following snippet compiles, unfortunately the result of the cached derived instance is always fixed to the type class, not the result of derives (so subclasses are lost): import scala.quoted.*
trait Show[A]:
inline def show(a: A): String
object Show:
given Show[Int] = new:
inline def show(a: Int): String = "Int"
inline def derived[T]: ShowGen[T] = ShowGen[T]()
class ShowGen[T] extends Show[T]:
inline def show(a: T): String = ${derivedImpl[T]}
def derivedImpl[T](using Quotes, Type[T]): Expr[String] =
Expr(Type.show[T]) Ideally the desugared code for case class M[A](x: A)
object M:
given Show_derived[A](using Show[A]): Show.ShowGen[M[A]] = Show.derived
@main def Test =
println(M.Show_derived.show(M(1))) |
Beta Was this translation helpful? Give feedback.
3 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Let's say we'd like to implement a
Show
typeclass which gives the most precise name of the type of a given instance (including generic parameters!). For example, for:println(summon[Show[M[Int]]].show(M(10)))
should giveM[Int]
.This is quite easy to do:
There are two problems when it comes to using the above in combination with
derives
. First, an attempt to simply adding thederives
toM
s definition fails:Second, even if it did work, as far as I understand it would generate the following code:
which also won't work, as the
derived
macro is called too early (when theshowSize
method is defined, not when it is called), causing our test program to outputM[A]
. To properly implement this, thegiven
needs to beinline
d:This works as expected.
But two questions remain:
case class M[A](x: A) derives Show
compile - maybe there is an issue for that, but I haven't been able to find one. My intuition is that it should generate code as in(*)
derives
did generate the code, it wouldn't work as expected. I suppose, we would need a way to tell the compiler to generate aninline given
in such a case. Moreover, this should be tied to the definition of the typeclass, not at usage-site. Would sth like@inlineDerives trait Show[A] { def show(a: A): String }
be theoretically possible?The example here is rather simplistic, but of course it comes from a more complicated use-case, here the use-case being derivation of
Schema
instances in tapir.Beta Was this translation helpful? Give feedback.
All reactions