Home > Software design >  Class companion object vs. case class itself
Class companion object vs. case class itself

Time:01-31

I read this statement:

By using User.getClass, you are referring to the class companion object that Scala by default creates for the case class, and not the case class itself.

To get the class object of the case class, use classOf[User].

Where could I come unstuck by using the class of the companion object? I would have thought - showing my ignorance here - they would be the same.

CodePudding user response:

Java has something called static methods

public class Foo {

  private int a:

  public Foo(a) { this.a = a; }

  public int getA() { return a; }

  static public String getB() { return "B"; }
}

it is like a method but not attached to an instance

var foo = new Foo(10);
foo.getA(); // method attached to foo, its value depends on foo

Foo.getB(); // method attached to class but not particular instance 

These static methods are used for storing globals (not recommended), or stateless functions not depending on object - like e.g. factories and other utilities. These methods can access private/protected members of the instances, and instances can access private/protected static methods - so you can limit visibility as if they were inside the object, even though they aren't (Java's reflection treats their methods as if they had null as this).

In Scala we didn't want to have the distinction for static and non-static methods so we decided to do the following:

  • create a separate object where such methods could be stored
  • make sure that this object could access instances members and vice-versa
  • have a similar name to distinct this object from other objects

That's how we arrived at companion object.

class Foo(val a: Int)
object Foo {
  val b = "B"
}
val foo = new Foo(10)
foo.a // this is normal method
foo.getClass // this would return Foo
class[Foo]   // same as above

Foo.getClass // this would return Foo$
classOf[Foo.type] // same as above

getClass is method that you can call on any object - since foo and Foo have different classes they would return different values for getClass.

Any value can describe their type with .type so foo.type would be the type of foo variable (Foo) and Foo.type would be the type of Foo object which is companion of Foo class (and would be called Foo$ in bytecode).

From the reason why companion object exist, it follows that Foo and its companion does not have the same (instance) methods, so they cannot have the same interface, and so they cannot be of the same type.

When it comes to case classes they just automatically create a companion object (if it doesn't exist) and generate some methods inside it based on their constructor: e.g. apply, unapply.

  • Related