Search code examples
scalatraitscompanion-object

Cannot call use class name directly to map type after adding a companion project


When we have a case class, we call map the type with the name of the type, e.g.:

case class Foo(value: String)
val value = Some("Yay!")
val foo = value.map(Foo)

But if we also provide a companion object, this stops working value.map(Foo) and looks like this works: value.map(Foo(_)). Why?

case class Foo(value: String)
object Foo {}
val value = Some("Yay!")
val foo = value.map(Foo)
println(foo)

ScalaFiddle.scala:5: error: type mismatch;
found : ScalaFiddle.this.Foo.type
required: scala.this.Function1[lang.this.String,?]
val foo = value.map(Foo)


Solution

  • If you don't define object Foo at all, then the synthetic companion object has the following declaration:

    <synthetic> object Foo 
       extends scala.runtime.AbstractFunction1[String,Foo] 
          with Serializable
    

    But if you define your own object Foo as follows

    case class Foo(v: String)
    object Foo {}
    

    then the declaration of the Foo object changes accordingly to:

    object Foo extends scala.AnyRef with Serializable
    

    and it no longer extends Function1.

    The method apply(v: String): Foo is still automatically generated on Foo, but it no longer implements the Function1[String, Foo] interface. If you declare the companion object like this:

    object Foo extends (String => Foo) { ... }
    

    then you again can use it in expressions like value.map(Foo).


    The value.map(Foo(_)) syntax always works, because it's just a shortcut for

    value.map(x => Foo.apply(x))
    

    and the closure doesn't care at all about what interfaces are implemented by Foo, it cares only about the existence of the apply method.