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
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Let's say we'd like to implement a
Showtypeclass 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 thederivestoMs 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
derivedmacro is called too early (when theshowSizemethod is defined, not when it is called), causing our test program to outputM[A]. To properly implement this, thegivenneeds to beinlined:This works as expected.
But two questions remain:
case class M[A](x: A) derives Showcompile - 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(*)derivesdid generate the code, it wouldn't work as expected. I suppose, we would need a way to tell the compiler to generate aninline givenin 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
Schemainstances in tapir.Beta Was this translation helpful? Give feedback.
All reactions