Skip to content

Instantly share code, notes, and snippets.

@samgj18
Created April 6, 2022 19:55
Show Gist options
  • Save samgj18/e72e7839cb1d31070a6dc29d2771f72b to your computer and use it in GitHub Desktop.
Save samgj18/e72e7839cb1d31070a6dc29d2771f72b to your computer and use it in GitHub Desktop.
case class Column[A](name: String)
object Column {
def string(name: String): Column[String] = Column[String](name)
def int(name: String): Column[Int] = Column[Int](name)
}
// Type arguments are unchecked because they are eliminated by erasure at runtime
def select[A](c: Column[A]): A = c match {
case _: Column[String] => "String"
case _: Column[Int] => 42
}
// select(Column.int("col1")) == 42 // this will throw a ClassCastException at runtime
/// How to fix this?
case class ColumnFix[A: ColumnType](name: String) { // ***
def columnType: ColumnType[A] = implicitly[ColumnType[A]]
}
// 1. Create a new trait to represent a column types
sealed trait ColumnType[A]
// 2. Create a companion object for each column type as implicit values
object ColumnType {
implicit case object StringColumnType extends ColumnType[String]
implicit case object IntColumnType extends ColumnType[Int]
}
object ColumnFix {
def string(name: String): ColumnFix[String] = ColumnFix[String](name)
def int(name: String): ColumnFix[Int] = ColumnFix[Int](name)
}
// 3. Create a function in the `ColumnFix` class that returns the type of the column and add a context bounded to the column type ***
// 4. Create a function to select a column with context bound to the column type.
// This will tell the compiler that we can call the function as long as there is an implicit instance for the column type defined for A.
def selectFix[A: ColumnType](c: ColumnFix[A]): A = c.columnType match {
case ColumnType.IntColumnType => 42
case ColumnType.StringColumnType => "String"
}
selectFix(ColumnFix.int("col1")) == 42
// res0: Boolean = true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment