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"))

10 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
  8. How do you use the companion constructor from another class? In other words, importing it and doing MyString("hello") or new MyString("hello"). I know it works with List, but I've tried your object and another one I'm working on, and am not able to compile any other class that constructs this object!

    ReplyDelete
  9. If you have a Companion object factory method then you just need to do:

    MyString("hello")

    ReplyDelete