Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save yingy4/d764532f84f6a79b5835fe2bb8c50eb9 to your computer and use it in GitHub Desktop.
Save yingy4/d764532f84f6a79b5835fe2bb8c50eb9 to your computer and use it in GitHub Desktop.
Scala: Case class, Companion object, Apply method and more

Scala Case class, Companion object, Apply method and more

Let’s take a look at some examples:

Example1:

object Tests extends App {
  println(Rating("PG",13))
  println(Rating.apply("PG",13)) //This is equivalent, so you don't need to explicitly call apply
}

case class Rating(code: String, age: Int)

The output is:

Rating(PG,13)
Rating(PG,13)

This will work since there is a Companion Object like this which is created by compiler, Note: there is a keyword new in the implementation of apply, this is the reason why apply method is like a constructor but not, because it just call the constructor for you.

object Rating {
  def apply(code: String, age: Int): Rating = new Rating(code, age)
}

Example2:

object Tests extends App {
  println(Rating("PG",13))
  println(Rating(13))
  println(Rating("PG"))
}

case class Rating(code: String, age: Int)

//We can append more apply method in Companion object, like we _Overloading_ constructor in Java, which is a form of polymorphism. Note we do not change the hidden apply method in this case, so the first println is still working.
object Rating {
  def apply(age: Int) = new Rating("PG", age) //You can have different apply method with different signature, you can also omit return type which can be inferred by compiler
  def apply(code: String) = code + "-" + 13 //You can also change the return type of apply method, so it can return a String instead of Object
}

The output is:

Rating(PG,13)
Rating(PG,13)
PG-13 //Note: This is a String not an Object

Example3:

object Tests extends App {
  println(Rating("PG",13))
}

case class Rating(code: String, age: Int)

//In this case we write an apply method with the same signature as case class defined
object Rating {
  def apply(code: String, age: Int): Rating = new Rating(code, age + 1) //We can "shadow" the compiler generated apply method. Note we are not overriding it since the apply method is not inheritance from parent.
  //def apply(code: String, age: Int): String = code + "-" + age //Like before, we can also change the return type
}

The output is:

Rating(PG,14)
//PG-13

Example4: This one will be a little confused:

object Tests extends App {
  println(Rating("PG",13))
  println(Rating("PG",13)("PG",13)("PG",13))
}

case class Rating(code: String, age: Int) {
  def apply(code: String, age: Int): Rating = new Rating(code, age + 1)
}

The output is:

Rating(PG,13)
Rating(PG,14)

In this case, we put apply method in case class, not companion object, although the apply method has the same signature as case class defined, but it actully in a totally different place, this apply method is for the object your created, not for creating the object.

So the first println use the apply method in compiler generated companion object, the second println use two apply method, the first one is compiler generated, the second and third one is the one we write in case class, which will return a Rating(PG,14)


Example5:

object Tests extends App {
  println(Rating("PG",13))
  println(Rating("PG",13)("PG",13)("PG",13))
}

case class Rating(code: String, age: Int) {
  def apply(code: String, age: Int): Rating = new Rating(code, this.age + 1)
}

This output is:

Rating(PG,13)
Rating(PG,15)

Can you think why it prints Rating(PG,15)? A hint: what is the difference between this.age and age in this case?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment