This is a followup on Shapeless and annotations. The original question was asked in the context of Scala 2 and Shapeless2.
Some features from Shapeless2 were migrated to Shapeless3, such as annotations. The question is, how to migrate the solution to Shapeless3? especially the code around Poly2?
Here is a copy/paste of the solution to be migrated to Shapeless3:
import shapeless.ops.hlist.{RightFolder, Zip}
import shapeless.{::, Annotations, Generic, HList, HNil, Lazy, Poly2}
import scala.annotation.StaticAnnotation
object App {
case class MyAnnotation(func: String) extends StaticAnnotation
object Collector extends Poly2 {
// implicit def myCase[ACC <: HList, E] = at[(E, Option[PII]), ACC] {
// case ((e, None), acc) => e :: acc
// case ((e, Some(MyAnnotation(func))), acc) => {
// println(func)
// e :: acc
// }
// }
implicit def someCase[ACC <: HList, E]: Case.Aux[(E, Some[MyAnnotation]), ACC, E :: ACC] = at {
case ((e, Some(MyAnnotation(func))), acc) =>
println(func)
e :: acc
}
implicit def noneCase[ACC <: HList, E]: Case.Aux[(E, None.type), ACC, E :: ACC] = at {
case ((e, None), acc) => e :: acc
}
}
trait Modifier[T] {
def modify(t: T): T
}
implicit def hListModifier[HL <: HList]: Modifier[HL] = identity(_)
// added as an example, you should replace this with your Modifier for HList
implicit def genericModifier[T, HL <: HList, AL <: HList, ZL <: HList](implicit
gen: Generic.Aux[T, HL],
ser: Lazy[Modifier[HL]],
annots: Annotations.Aux[MyAnnotation, T, AL],
zip: Zip.Aux[HL :: AL :: HNil, ZL],
rightFolder: RightFolder.Aux[ZL, HNil/*.type*/, Collector.type, HL /*added*/]
): Modifier[T] = new Modifier[T] {
override def modify(t: T): T = {
val generic = gen.to(t)
println(generic)
val annotations = annots()
println(annotations)
val zipped = zip(generic :: annotations :: HNil)
println(zipped)
val modified = zipped.foldRight(HNil : HNil /*added*/)(Collector)
println(modified)
val typed = gen.from(modified)
typed
}
}
case class Test(a: String, @MyAnnotation("sha1") b: String)
val test = Test("A", "B")
val modifier: Modifier[Test] = implicitly[Modifier[Test]]
def main(args: Array[String]): Unit = {
val test1 = modifier.modify(test) // prints "sha1"
println(test1) // Test(A,B)
}
}
In Scala 3
Tupleis forHList,Mirroris forGeneric/LabelledGeneric. There are polymorphic functions but they are parametric-polymorphism polymorphic, not ad-hoc-polymorphism polymorphic likePoly.Shapeless 3 has
Annotations,Typeableand deriving tools (wrappingMirror).It's not hard to implement missing pieces (
Generic,Coproduct,Poly, type classes etc.)Scala 3 collection partitioning with subtypes
Maybe some of type classes can be replaced with match types or compile-time calculations.
It can be tricky to implement
Lazy. It's not clear whether it's needed. There are by-name implicits but they are not equivalent toLazy(1 2). In principle,Lazycan be implemented in Scala 3 since compiler internals for implicits in Scala 3 are similar to those in Scala 2 (1 2 3).Shapeless and annotations
Here is simpler solution for Scala 3