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
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