Constructor pattern match: constructor cannot be instantiated to expected type

Hi,

consider the following code:

trait Base
trait Extension

case class A(a: Int) extends Base
case class B(b: String) extends Base

object Main {
  type Extend[+T <: Base] = T with Extension

  def main(args: Array[String]): Unit = {
    val objs = List(new A(8) with Extension , new B("hi") with Extension)
    ok(objs)
    notOk(objs)
  }

  def ok(objs: List[Extend[Base]]): Unit = {
    objs collect {
      case o: A => println(o.a)
      case o: B => println(o.b)
    }
  }

  def notOk(objs: List[Extend[Base]]): Unit = {
    objs collect {
      case A(a) => println(a)
      case B(b) => println(b)
    }
  }
}

Compiling this in Scala 2.12.2 yields:

$ scalac repro.scala 
repro.scala:27: error: constructor cannot be instantiated to expected type;
 found   : A
 required: Base with Extension
      case A(a) => println(a)
           ^
repro.scala:28: error: constructor cannot be instantiated to expected type;
 found   : B
 required: Base with Extension
      case B(b) => println(b)
           ^
two errors found

Is this expected behavior? I would have expected a constructor pattern match to be possible in this case.

1 Like

Hi,

Yes, while typed patterns like case o: A => … allow you to match "anything which is an instance of A", constructor patterns are a bit more restrictive: they must match the expected type of the pattern matching.

In the second example, the expected type of the pattern-matching is Base with Extension (aka Extend[Base]) but the A and B constructors produce values of type Base which is not an instance of Base with Extension. That is why it does not compile.

A way around this could be to define two extractor objects:

object ExtA {
  def unapply(ae: A with Extension): Option[Int] = Some(ae.a)
}

object ExtB {
  def unapply(be: B with Extension): Option[String] = Some(be.b)
}

Then you can write

def printAll(objs: List[Extend[Base]]): Unit = {
  objs foreach {
    case ExtA(a) => println(a)
    case ExtB(b) => println(b)
  }
}

which still has the nice looking of constructor patterns and type-checks.