Skip to content

Instantly share code, notes, and snippets.

@sagoez
Created April 6, 2022 19:55
Show Gist options
  • Select an option

  • Save sagoez/e72e7839cb1d31070a6dc29d2771f72b to your computer and use it in GitHub Desktop.

Select an option

Save sagoez/e72e7839cb1d31070a6dc29d2771f72b to your computer and use it in GitHub Desktop.

Revisions

  1. sagoez created this gist Apr 6, 2022.
    48 changes: 48 additions & 0 deletions erasure.worksheet.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,48 @@

    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