} object CsvEncoder { implicit val personEncoder = new CsvEncoder[Person] { override def encode(value: Person): List[String] = List( value.name, value.age.toString, if (value.isManager) "yes" else "no" ) } implicit val dogEncoder = new CsvEncoder[Dog] { override def encode(value: Dog): List[String] = List( value.name, value.age.toString, if (value.woolly) "yes" else "no" ) } implicit class CsvEncoderOps[A](value: A) { def asCsv(implicit enc: CsvEncoder[A]): String = enc.encode(value).mkString(",") } // Or //implicit class CsvEncoderOps[A](value: A) { // def asCsv: String = implicitly[CsvEncoder[A]].encode(value).mkString(",") //} } object Main extends App { import CsvEncoder._ case class Person(name: String, age: Int, isManager: Boolean) case class Dog(name: String, age: Int, woolly: Boolean) val person = Person("person", 29, true) val dog = Dog("dog", 10, false) println(person.asCsv) println(dog.asCsv) }