Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala pattern matching with manifest

This great daily Scala article describes how to overcome type erasure in matching. I'm trying to apply the technique to transform an IndexesSeq of parameterised types, but the matches are failing. Why is this, and how can I fix it?

object Example extends App{
    class TableColumn[T](
        val values: IndexedSeq[T], 
        val name: Option[String] = None
    )(implicit val m: Manifest[T])

    class Def[C](implicit desired : Manifest[C]) {
        def unapply[X](c : X)(implicit m : Manifest[X]) : Option[C] = {
            //println("m.toString+", "+desired.toString)
            def sameArgs = desired.typeArguments.zip(m.typeArguments).forall {
                case (desired,actual) => desired >:> actual
            }
            if (desired >:> m && sameArgs) Some(c.asInstanceOf[C])
            else None
         }
    }

    val IntTableColumn = new Def[TableColumn[Int]]
    val DoubleTableColumn = new Def[TableColumn[Double]]

    class Analysis(data: IndexedSeq[TableColumn[_]]){
        val transformedData = data.map{_ match{
            case IntTableColumn(tc) => println("Column of Int! "+ tc)
            case DoubleTableColumn(tc) => println("Column of Double! "+ tc)
            case _ => println("no match")
        }}
    }

    new Analysis(IndexedSeq(
            new TableColumn(IndexedSeq(1,2,3)),
            new TableColumn(IndexedSeq(1.0,2.0,3.0))
    ))
}

If I uncomment the line in Def then I see lines such as

prototype.Example$TableColumn[_ <: Any], prototype.Example$TableColumn[Int]

suggesting that the _ in the Analysis constructor is the problem, but I don't know what else to put in there.

like image 463
Pengin Avatar asked Aug 14 '12 16:08

Pengin


1 Answers

Thanks to comments from Rex Kerr I've cobbled together something that I think works. It can probably done more elegantly/generally, but it seems to get the job done for now:

object Example extends App{
    class TableColumn[T](
            val values: IndexedSeq[T], 
            val name: Option[String] = None
    )(implicit val m: Manifest[T])

    class TableColumnMatcher[T](implicit desired: Manifest[T]){
        def unapply(tc: TableColumn[_]): Option[TableColumn[T]] = {
            if(tc.m == desired) Some(tc.asInstanceOf[TableColumn[T]])
            else None
        }
    }
    object TableColumnMatcher{
        lazy val IntTC = new TableColumnMatcher[Int]
        lazy val DoubleTC = new TableColumnMatcher[Double]
    }


    class Analysis(data: IndexedSeq[TableColumn[_]]){
        import TableColumnMatcher._
        val transformedData = data.map{_ match{
            case IntTC(tc) => println("Column of Ints!"); 
            case DoubleTC(tc) => println("Column of Doubles!")
            case _ => println("no match")
        }}
    }

    new Analysis(IndexedSeq(
            new TableColumn(IndexedSeq(1,2,3)),
            new TableColumn(IndexedSeq(1.0,2.0,3.0))
    ))
}
like image 102
Pengin Avatar answered Sep 29 '22 12:09

Pengin