Error compiling `tupleToCsv` from the Scala blog

Scala Blog post “Tuples bring generic programming to Scala 3” shows an interesting example of converting a tuple to CSV using new Scala 3 features.

When I try to compile the code from the first part of the blog I am getting error:

no implicit argument of type blog210226.RowEncoder[(String, Int, Boolean)] was found for an implicit parameter of method tupleToCsv in package blog210226

The following import might make progress towards fixing the problem:

  import blog210226.TupleEncoders.given_RowEncoder_*:

Here us the code that I copied from the blog (added package):

package blog210226

trait FieldEncoder[A]:
  def encodeField(a: A): String

type Row = List[String]

trait RowEncoder[A]:
  def encodeRow(a: A): Row


object BaseEncoders:
  given FieldEncoder[Int] with
    def encodeField(x: Int) = x.toString

  given FieldEncoder[Boolean] with
    def encodeField(x: Boolean) = if x then "true" else "false"

  given FieldEncoder[String] with
    def encodeField(x: String) = x 
end BaseEncoders


object TupleEncoders:
  // Base case
  given RowEncoder[EmptyTuple] with
    def encodeRow(empty: EmptyTuple) =
      List.empty

  // Inductive case
  given [H: FieldEncoder, T <: Tuple: RowEncoder]: RowEncoder[H *: T] with
    def encodeRow(tuple: H *: T) = 
      summon[FieldEncoder[H]].encodeField(tuple.head) :: summon[RowEncoder[T]].encodeRow(tuple.tail)

end TupleEncoders


def tupleToCsv[X <: Tuple : RowEncoder](tuple: X): List[String] =
  summon[RowEncoder[X]].encodeRow(tuple)


def main(args: Array[String]): Unit =
  // This does not compile, why?
  val csv = tupleToCsv(("Bob", 42, false))
  println(csv)

When I try to add the import suggested in the error:

def main(args: Array[String]): Unit =
  import blog210226.TupleEncoders.given_RowEncoder_*:
  // This does not compile, why?
  val csv = tupleToCsv(("Bob", 42, false))
  println(csv)

The error changes to:

no implicit argument of type blog210226.RowEncoder[(String, Int, Boolean)] was found for an implicit parameter of method tupleToCsv in package blog210226.
I found:

    blog210226.TupleEncoders.given_RowEncoder_*:[H, T](
      /* missing */summon[blog210226.FieldEncoder[String]]
    , ???)

But no implicit values were found that match type blog210226.FieldEncoder[String].
  val csv = tupleToCsv(("Bob", 42, false))

Am I missing something?

1 Like

To make it easy and quick for others to assist, here’s a Scastie link to the initial code you provided:

1 Like

In the original code those encoders are not in the implicit scope thus are not found, you can add them to the implicit scope either with an import or usually those are put in the companion objects of their typeclasses.

3 Likes

Thanks for the corrections. Looks that implicit scopes got “disconnected” and inheritance “connected” them:

object FieldEncoder extends BaseEncoders
object RowEncoder extends TupleEncoders

For future reference I simplified to code slightly:

3 Likes

Here is another solution:

I think the issue is in scala 3, the import TupleEncoders.* does not import the givens? I seemed to have to explicitly add given:

  import BaseEncoders.{given}
  import TupleEncoders.{given}
2 Likes