Reputation: 5023
Occasionally, I found an interesting feature of case class. The foo needs a function which 3 Int to a case class, The code looks like this:
case class Whatever(a: Int, b: Int, c: Int)
def foo(f: (Int, Int, Int) => Whatever) = f(1,2,3).c
foo(Whatever) //compilation fine, scala complier is powerful ...........
If Whatever is normal class, obviously, the compilation will fail.
Can someone explain why case class can be used this way, I suspect it is the reason of factory apply method, but I am not sure. Also, if it is a normal class, is it possible to use it this way as case class.
Upvotes: 2
Views: 100
Reputation: 5023
Thanks for @planetenkiller @gzm0 explanation, so if I want to normal class has the same behavior. Here is the implementation.
class Whatever(a: Int, b: Int, c: Int)
object Whatever extends ((Int, Int, Int) => Whatever) {
def apply(a: Int, b: Int, c: Int): Whatever = {
new Whatever(a, b, c)
}
}
def foo(f: (Int, Int, Int) => Whatever) = f(1,2,3)
foo(Whatever)
Upvotes: 0
Reputation: 14842
As @planetenkiller mentioned, if you create a case class, the compiler automatically generates a companion object with a couple of methods.
It notably implements apply
and unapply
which allow you to do the following:
val x = Whatever(1,2,3) // is actually Whatever.apply(1,2,3)
x match {
case Whatever(x,y,z) => // uses Whatever.unapply
/* ... */
}
Further, it extends FunctionN
with the right number of arguments. Therefore, a companion object of a case class is a function. Therefore, it becomes obvious that you may use it as a function (i.e. for once, there is no magic on the call site).
val x: Function3[Int, Int, Int, Whatever] = {
Whatever // compiles, no implicit conversion
}
Upvotes: 3
Reputation: 714
The scala compiler generates a companion object for a case class and implements a few things (implement AbstractFunction3, apply, unapply):
javap Whatever\$.class
Compiled from "Test.scala"
public final class Whatever$ extends scala.runtime.AbstractFunction3<java.lang.Object, java.lang.Object, java.lang.Object, Whatever> implements scala.Serializable {
public static final Whatever$ MODULE$;
public static {};
public final java.lang.String toString();
public Whatever apply(int, int, int);
public scala.Option<scala.Tuple3<java.lang.Object, java.lang.Object, java.lang.Object>> unapply(Whatever);
public java.lang.Object apply(java.lang.Object, java.lang.Object, java.lang.Object);
}
Upvotes: 3