Because there's no relationship between FunctionN
types in Scala, it's not possible to do this without arity-level boilerplate somewhere—there's just no way to abstract over the companion objects' apply
methods without enumerating all the possible numbers of members.
You could do this by hand with a bunch of CompanionN[A, B, C, ...]
traits, but that's pretty annoying. Shapeless provides a much better solution, which allows you to write something like the following:
import shapeless.{ Generic, HList }, shapeless.ops.product.ToHList
class CaseClassCompanion[C] {
def tupled[P <: Product, R <: HList](p: P)(implicit
gen: Generic.Aux[C, R],
toR: ToHList.Aux[P, R]
): C = gen.from(toR(p))
}
And then:
case class Book(id: Int, isbn: String, name: String)
object Book extends CaseClassCompanion[Book]
case class Author(id: Int, name: String)
object Author extends CaseClassCompanion[Author]
Which you can use like this:
scala> Book.tupled((0, "some ISBN", "some name"))
res0: Book = Book(0,some ISBN,some name)
scala> Author.tupled((0, "some name"))
res1: Author = Author(0,some name)
You might not even want the CaseClassCompanion
part, since it's possible to construct a generic method that converts tuples to case classes (assuming the member types line up):
class PartiallyAppliedProductToCc[C] {
def apply[P <: Product, R <: HList](p: P)(implicit
gen: Generic.Aux[C, R],
toR: ToHList.Aux[P, R]
): C = gen.from(toR(p))
}
def productToCc[C]: PartiallyAppliedProductToCc[C] =
new PartiallyAppliedProductToCc[C]
And then:
scala> productToCc[Book]((0, "some ISBN", "some name"))
res2: Book = Book(0,some ISBN,some name)
scala> productToCc[Author]((0, "some name"))
res3: Author = Author(0,some name)
This will work for case classes with up to 22 members (since the apply
method on the companion object can't be eta-expanded to a function if there are more than 22 arguments).
fromTuple
might be a better name for this method—it's true that you're tupling theapply
, but calling the resulttupled
makes is sound like the conversion is to a tuple instead of from. – Frasquito