softwaremill / magnolia

Easy, fast, transparent generic derivation of typeclass instances
https://softwaremill.com/open-source/
Apache License 2.0
754 stars 115 forks source link

Support heterogenous typeclass derivation #503

Open gpoulin opened 6 months ago

gpoulin commented 6 months ago

There's cases where the typeclass we want to derive from a case class is a super-type of the typeclass. One such example is the JSON encoding typeclass in play-json which look likes the following:

trait Writes[A] {
  def writes(o: A): JsValue
}

trait OWrites[A] extends Writes[A] {
  def writes(o: A): JsObject
}

In this example, OWrites is a Writes that guarantees that the JsValue is actually a JsObject. I would like to be able to derive the OWrites typeclass on case class using Magnolia. AFAIK, this is currently not possible since the parameters of the case class don't always have an implementation for OWrites, but sometime just an implementation for Writes.

Apriori (I'm likely missing something), making a small change to the interface would make that possible for scala 3

trait CommonHeteroDerivation[TypeClass[_], ParamTypeClass[_]]:
  def join[T](caseClass: CaseClass[ParamTypeclass, T]): Typeclass[T]
end CommonHeteroDerivation

trait CommonDerivation[TypeClass[_]] extends CommonHeteroDerivation[TypeClass, TypeClass]

The change for scala 2 would be more involved.

The same concept could be applied to sealed trait derivation, but the use cases are less obvious.