Scala3 Tuple - iterate over elements to convert them

I’m interested in trying to support Scala3 in GitHub - kontainers/PureCSV: A type-safe and boilerplate-free CSV library for Scala.

One of the things I need to do is to convert a case class into a Seq[String] by calling StringConverter instances that are declared as implicits. In Scala 2, this works with shapeless features that don’t appear in shapeless3.

The current code converts the case class to a HList and I’m trying to use a Scala 3 Tuple instead.

In this scastie example - I can get the implicit to work when accessing a specific element in the tuple. If I try to iterate using a Tuple.map or a for comprehension, the compiler cannot match the implicits.

Does anyone have any ideas how this can be fixed?

1 Like

It seems that you cannot use Tuple.map in this case, since the converter would have to be given to the inner function as an extra parameter list and that clashes with the prototype specified by map.

You would have to do it by recursion (see Tuples bring generic programming to Scala 3 | The Scala Programming Language) like this:

trait StringConverter[T] {
  def convert(t: T): String
}

object StringConverter {
  def convert[T](t: T)(using conv: StringConverter[T]): String = conv.convert(t)
}

given StringConverter[EmptyTuple] with
  def convert(empty: EmptyTuple) =
    ""

// Inductive case
given [H: StringConverter, T <: Tuple: StringConverter]: StringConverter[H *: T] with
  def convert(tuple: H *: T) =
    StringConverter.convert(tuple.head) + StringConverter.convert(tuple.tail)

@main def main = {
  val tuple = ("abc", 123, BigDecimal("1.23"))

  println(StringConverter.convert(tuple))  // string=abcint=123big-decimal=1.23
}

Now, String concatenation might not be what you want, but you could adapt this to use a List instead, which is probably what you want anyway.

1 Like

Thank @cbley - I took your example and got scastie sample to work