I propose to introduce a type class into the standard library that can capture the idea of converting from one type to another in a lossless way. Note, I’ll use Scala 2 syntax here because I’m more familiar with it but happy to switch to 3 if this discussion progresses.
trait As[A, B] {
def apply(a: A): B
}
trait LowPrioImplicits {
// Etc.
implicit def seq[A, B](implicit AAsB: A As B): Seq[A] As Seq[B] = _.map(AAsB.apply)
}
object As extends LowPrioImplicits {
// Extension method
implicit class Ops[A](private val a: A) extends AnyVal {
def as[B](implicit AsB: A As B): B = AsB(a)
}
}
Why a new type class? Throughout Scala, both in the standard library and elsewhere, we see many examples of converting from one type to another. E.g, scala/AsScalaExtensions.scala at 986dcc160aab85298f6cab0bf8dd0345497cdc01 · scala/scala · GitHub
import scala.jdk.CollectionConverters.ListHasAsScala
val javaList: java.util.List[Int] = ...
val scalaSeq: Seq[Int] = javaList.asScala
With the As
type class, we could represent this as:
implicit def javaListAsScalaSeq[A]: java.util.List[A] As Seq[A] = ...
Now, we could just do: val scalaSeq: Seq[Int] = javaList.as
This doesn’t stop at just JDK/Scala type conversions, imagine third-party libraries representing e.g. JSON codecs like:
type Decoder[A] = Json As A
type Encoder[A] = A As Json
...
case class MyDomainType(wow: Int)
object MyDomainType {
implicit val asJson: MyDomainType As Json = derive
}
val payload: Json = myDomainType.as
In fact having a standardized As
type class` would make redundant a bunch of specialized types and implicits that exist just to represent the concept of a conversion from one type to another. The type class just generalizes the concept of ‘convert type A to B’.
You might ask, doesn’t a function type A => B
represent that already? Yes it does but I think it’s too general. It can mean anything in different contexts. We need something that semantically means ‘transform A to represent it as B’.
Prior art: Rust’s From trait which captures the concept of ‘convert from type T to this type’. However in Scala we can do a type class with two parameters which is more general-purpose.