0

in Scala 3, I'm trying to instantiate a case class from a list of String, example

the list List("bob", "2.2", "1") fit the fields of Foo:

case class Foo(aString: String, aDouble: Double, aInt: Int)

and listStringTOclass[Foo](List("bob", "2.2", "1")) returns Foo(bob,2.2,1)

But I can't retrive the types of Foo elements, in my code I wrote val types = List("String", "Double", "Int") but I should use MirroredElemTypes to generalize, any help?

    import scala.deriving.Mirror
    import scala.compiletime.summonAll

    def listStringTOclass[A](stringValues:List[String])(using m: Mirror.ProductOf[A]) = {
      type TheType = String
      type StringValue = String

      val types = List("String","Double","Int") // m.MirroredElemTypes, should be Type not string

      def valueList(ll: List[(TheType, StringValue)]): List[Any] = ll match {
        case Nil => Nil
        case h::t if h._2 == "String" => h._1 :: valueList(t)
        case h::t if h._2 == "Int"    => h._1.toInt :: valueList(t)
        case h::t if h._2 == "Double" => h._1.toDouble :: valueList(t)
        case _ => ???
      }

      val tv: List[(TheType, StringValue)] = stringValues.zip(types)
      val l: List[Any] = valueList(tv)
      println(l) // List(bob, 2.2, 1)
      val tuple: Tuple = l.foldRight[Tuple](EmptyTuple)(_ *: _)
      println(tuple) //  (bob,2.2,1)

      m.fromProduct(tuple)
    }


    case class Foo(aString: String, aDouble: Double, aInt: Int)

    val o = listStringTOclass[Foo](List("bob", "2.2", "1"))
    println(o) // Foo(bob,2.2,1)
gekomad
  • 525
  • 9
  • 17
  • 2
    Are you trying to write a CSV parser or something similar by chance? – Luis Miguel Mejía Suárez Sep 06 '21 at 15:12
  • As far as I understood your problem, you can use reflection in this case (wether runtime or compile time, for instance, if you have used play json, Json.writer[T] creates a Writer for type T in compile time, but parsing a json into an object is done at runtime), you have access to a type or object's public and private field names, methods and types and so many other things. and also, what would happen if your Foo class has an object of another complex class? so I would recommend you to use reflection. – AminMal Sep 06 '21 at 15:59
  • 1
    This might help: https://stackoverflow.com/questions/14722860/convert-a-scala-list-to-a-tuple, then tuple to case class is OOB – Gaël J Sep 06 '21 at 18:10

2 Answers2

2

How about this (works in scala 3.0.1):

scala> object list2class {
     |   import scala.deriving.Mirror
     |
     |   trait Decoder[A, B] extends (A => B)
     |   object Decoder:
     |     given Decoder[String, String] = s => s
     |     given Decoder[String, Int] = _.toInt
     |     given Decoder[String, Double] = _.toDouble
     |     given Decoder[List[String], EmptyTuple] = {
     |       case Nil => EmptyTuple
     |       case s => throw IllegalArgumentException(s.toString())
     |     }
     |     given [H, T <: Tuple](using dh: Decoder[String, H], dt: Decoder[List[String], T]): Decoder[List[String], H *: T] = {
     |       case h::t => dh(h) *: dt(t)
     |       case Nil => throw IndexOutOfBoundsException()
     |     }
     |
     |   def apply[A](xs: List[String])(using m: Mirror.ProductOf[A], d: Decoder[List[String], m.MirroredElemTypes]): A =
     |     m.fromProduct(d(xs))
     | }
// defined object list2class

scala> case class Foo(aString: String, aDouble: Double, aInt: Int)
// defined case class Foo

scala> list2class[Foo](List("bob", "2.2", "1"))
val res0: Foo = Foo(bob,2.2,1)
esse
  • 1,415
  • 5
  • 10
0

Consider using shapeless for semi-automatic case class derivation via HList "heterogeneous list".

mrmizz
  • 1
  • 2