views:

370

answers:

3
object Test extends Application {

  // compiles:
  Map[Int, Value](
    0 -> KnownType(classOf[Object]),
    1 -> UnknownValue())

  // does not compile:
  Map(
    0 -> KnownType(classOf[Object]),
    1 -> UnknownValue())
}
sealed trait Value {
  def getType: Option[Class[_]]
}
case class UnknownValue() extends Value {
  def getType = None
  // compiles if changed to:
  // def getType: Option[Class[_]] = None
}
case class KnownType(typ: Class[_]) extends Value {
  def getType = Some(typ)
}

The above code fails to compile. The compiler's error message is:

Experiment.scala:10: error: type mismatch;
 found   : (Int, KnownType)
 required: (Int, Product with Value{def getType: Option[java.lang.Class[_$2]]}) where type _$2
    0 -> KnownType(classOf[Object]),
      ^
one error found

If I change the method declaration of UnknownValue to be def getType: Option[Class[_]] = None then also the Map() without type parameters compiles.

Why?

+1  A: 

Hmm, that is weird. Looks like a bug to me.

One way you can fix it is by giving Value a default value for getType, then only overriding it in KnownType. Like so:

sealed trait Value {
  def getType: Option[Class[_]] = None
}

case object UnknownValue extends Value

case class KnownType(typ: Class[_]) extends Value {
  override def getType = Some(typ)
}

But that looks suspiciously like you're reinventing Option. I'd skip the Value type altogether, and just use straight Options.

Map(
  0 -> Some(classOf[Object]),
  1 -> None)

If you don't like typing Option[Class[_]] every time you expect one of these Maps, you can create an alias for it:

type Value = Option[Class[_]]
Jorge Ortiz
This is a minimal example for reproducing the issue. In the real code there are also other case classes, so it's not just reinventing Option.
Esko Luontola
+1  A: 

It does look like a bug, but there are many issues with type inference which can easily be worked around by giving it a little help. It compiles like this:

Map(
  0 -> KnownType(classOf[Object]),
  1 -> (UnknownValue() : Value))
extempore
A: 

I posted the question to the scala-user mailing list and also they said that it's a bug.

Esko Luontola