Xiaohe Dong
Xiaohe Dong

Reputation: 5023

why case class can be used as a function in the argument

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

Answers (3)

Xiaohe Dong
Xiaohe Dong

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

gzm0
gzm0

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

planetenkiller
planetenkiller

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

Related Questions