2
votes

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)

1
I just paste the code in the RELP and it worked (scala 2.12.7), which Scala version are you using? or can you provide a more complete example that does fail?Luis Miguel Mejía Suárez
@LuisMiguelMejíaSuárez I just tried it in a worksheet and it doesn't work: scalafiddle.io/sf/nXeDmV1/0 - what did you do to make it compile?James Whiteley
@LuisMiguelMejíaSuárez, code added, and we're running 2.11.8.Yuchen

1 Answers

3
votes

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.