Hello all, Scala 3 has built conversion from a case class into a Tuple, via Tuple.fromProductTyped
. It would be great to have a similar nice api in the opposite direction, i.e. from a Tuple into a case class:
extension (tuple: Tuple) inline def to[T](using m: Mirror.ProductOf[T]): T = m.fromProduct(tuple)
case class A(x: Int, y: String)
(1, "a").to[A]
What do you think about adding this extension? Without it, the current solution looks like this, arguably non-discoverable and frightening for and average user:
summon[deriving.Mirror.ProductOf[A]].fromProduct((1, "a"))
1 Like
If it does not need to be generic you can use A.apply.tupled
, or we can create an easy wrapper on top of mirrors (there isn’t really anything scary about them)
case class Foo(a: Int, b: Long)
extension [T <: Tuple](tuple: T)
inline def to[V](using p: scala.deriving.Mirror.ProductOf[V], evidence: p.MirroredElemTypes =:= T): V =
p.fromTuple(tuple.asInstanceOf[p.MirroredElemTypes])
@main def Test =
val usingNamedTuples = Foo.apply.tupled((a = 42, b = 24L))
val usingTuples = Foo.apply.tupled((42, 24L))
val usingMirrors = (0, 1L).to[Foo]
val usingNamedMirrors = (a = 1, b = 0L).to[Foo]
The asInstanceOf
is safe here because I have evidence that my tuple matches the type of tuple created from the product.
The version based on fromProduct
is unsafe because we can’t check at compile time that the tuple matches the type T, leading to possible error at runtime
I think it might be a good idea to include something like that in standard library
6 Likes
We might even get rid of asInstanceOf
:
extension [T <: Tuple](tuple: T) {
inline def to[V](using p: scala.deriving.Mirror.ProductOf[V], evidence: T =:= p.MirroredElemTypes): V =
p.fromTuple(evidence(tuple))
}
5 Likes