Wednesday, September 9, 2009

Companion Object

A companion object is an object with the same name as a class or trait and is defined in the same source file as the associated file or trait. A companion object differs from other objects as it has access rights to the class/trait that other objects do not. In particular it can access methods and fields that are private in the class/trait.

An analog to a companion object in Java is having a class with static methods. In Scala you would move the static methods to a Companion object.

One of the most common uses of a companion object is to define factory methods for class. An example is case-classes. When a case-class is declared a companion object is created for the case-class with a factory method that has the same signature as the primary constructor of the case class. That is why one can create a case-class like: MyCaseClass(param1, param2). No new element is required for case-class instantiation.

A second common use-case for companion objects is to create extractors for the class. I will mention extractors in a future topic. Basically extractors allow matching to work with arbitrary classes.

NOTE: Because the companion object and the class must be defined in the same source file you cannot create them in the interpreter. So copy the following example into a file and run it in script mode:

scala mysourcefile.scala


Example:

  1. class MyString(val jString:String) {
  2.   privatevar extraData = ""
  3.   overridedef toString = jString+extraData
  4. }
  5. object MyString {
  6.   def apply(base:String, extras:String) = {
  7.     val s = new MyString(base)
  8.     s.extraData = extras
  9.     s
  10.   }
  11.   def apply(base:String) = new MyString(base)
  12. }
  13. println(MyString("hello"," world"))
  14. println(MyString("hello"))

8 comments:

  1. I am a beginner in Scala.
    How test the above code in REPL for Scala?
    Appreciate your answer.
    Thanks

    ReplyDelete
  2. In the REPL there are a couple of tricks, the easiest is to surround the example in an object:

    scala> object Around {
    | class MyString(val jString:String) {
    | private var extraData = ""
    | override def toString = jString+extraData
    | }
    | object MyString {
    | def apply(base:String, extras:String) = {
    | val s = new MyString(base)
    | s.extraData = extras
    | s
    | }
    | def apply(base:String) = new MyString(base)
    | }
    | println(MyString("hello"," world"))
    | println(MyString("hello"))
    | }
    defined module Around

    scala> Around
    hello world
    hello
    res5: Around.type = Around$@1ab9dac

    ReplyDelete
  3. Find your posts useful Jesse, thx.

    ReplyDelete
  4. copy the code into a file.
    open the REPL and type ":load "

    (do not include triangular brackets, and do not use quotes around the filename. Use full file pathname)

    ReplyDelete
  5. In the Scala REPL you can use the :paste command to enter paste mode which will allow you to paste in the contents as if it were a single file.

    ReplyDelete
  6. Did the ability to access private fields in the class from the companion object change recently in Scala? In 2.10 I get a compile error unless I remove the "private" from "s".

    ReplyDelete
  7. It is also used to resolve implicit parameter

    ReplyDelete