# Companion Objects

Member functions act on particular instances of a class. Some functions aren’t “about” an object, so they don’t need to be tied to that object.

Functions and fields inside companion objects are about the class. Regular class elements can access the elements of the companion object, but the companion object elements cannot access the regular class elements.

As you saw in [Objects](javascript:void(0)), it’s possible to define a regular object inside a class, but that doesn’t provide an association between the object and the class. In particular, you’re forced to explicitly name the nested object when you refer to its members. If you define a companion object inside a class, its elements become transparently available to that class:

// CompanionObjects/CompanionObject.kt
package companionobjects
import atomictest.eq

class WithCompanion {
  companion object {
    val i = 3
    fun f() = i * 3
  }
  fun g() = i + f()
}

fun WithCompanion.Companion.h() = f() * i

fun main() {
  val wc = WithCompanion()
  wc.g() eq 12
  WithCompanion.i eq 3
  WithCompanion.f() eq 9
  WithCompanion.h() eq 27
}

Outside the class, you access members of the companion object using the class name, as in WithCompanion.i and WithCompanion.f(). Other members of the class can access the companion object elements without qualification, as you see in the definition of g().

h() is an extension function to the companion object.

If a function doesn’t require access to private class members, you can choose to define it at file scope rather than putting it in a companion object.

Only one companion object is allowed per class. For clarity, you can give the companion object a name:

// CompanionObjects/NamingCompanionObjects.kt
package companionobjects
import atomictest.eq

class WithNamed {
  companion object Named {
    fun s() = "from Named"
  }
}

class WithDefault {
  companion object {
    fun s() = "from Default"
  }
}

fun main() {
  WithNamed.s() eq "from Named"
  WithNamed.Named.s() eq "from Named"
  WithDefault.s() eq "from Default"
  // The default name is "Companion":
  WithDefault.Companion.s() eq "from Default"
}

Even when you name the companion object you can still access its elements without using the name. If you don’t give the companion object a name, Kotlin assigns it the name Companion.

If you create a property inside a companion object, it produces a single piece of storage for that field, shared with all instances of the associated class:

// CompanionObjects/ObjectProperty.kt
package companionobjects
import atomictest.eq

class WithObjectProperty {
  companion object {
    private var n: Int = 0 // Only one
  }
  fun increment() = ++n
}

fun main() {
  val a = WithObjectProperty()
  val b = WithObjectProperty()
  a.increment() eq 1
  b.increment() eq 2
  a.increment() eq 3
}

The tests in main() show that n has only a single piece of storage, no matter how many instances of WithObjectProperty are created. a and b both access the same memory for n.

increment() shows that you can access private members of the companion object from its surrounding class.

When a function is only accessing properties in the companion object, it makes sense to move that function inside the companion object:

// CompanionObjects/ObjectFunctions.kt
package companionobjects
import atomictest.eq

class CompanionObjectFunction {
  companion object {
    private var n: Int = 0
    fun increment() = ++n
  }
}

fun main() {
  CompanionObjectFunction.increment() eq 1
  CompanionObjectFunction.increment() eq 2
}

You no longer need a CompanionObjectFunction instance to call increment().

Suppose you’d like to keep a count of every object you create, to give each one a unique readable identifier:

// CompanionObjects/ObjectCounter.kt
package companionobjects
import atomictest.eq

class Counted {
  companion object {
    private var count = 0
  }
  private val id = count++
  override fun toString() = "#$id"
}

fun main() {
  List(4) { Counted() } eq "[#0, #1, #2, #3]"
}

A companion object can be an instance of a class defined elsewhere:

// CompanionObjects/CompanionInstance.kt
package companionobjects
import atomictest.*

interface ZI {
  fun f(): String
  fun g(): String
}

open class ZIOpen : ZI {
  override fun f() = "ZIOpen.f()"
  override fun g() = "ZIOpen.g()"
}

class ZICompanion {
  companion object: ZIOpen()
  fun u() = trace("${f()} ${g()}")
}

class ZICompanionInheritance {
  companion object: ZIOpen() {
    override fun g() =
      "ZICompanionInheritance.g()"
    fun h() = "ZICompanionInheritance.h()"
  }
  fun u() = trace("${f()} ${g()} ${h()}")
}

class ZIClass {
  companion object: ZI {
    override fun f() = "ZIClass.f()"
    override fun g() = "ZIClass.g()"
  }
  fun u() = trace("${f()} ${g()}")
}

fun main() {
  ZIClass.f()
  ZIClass.g()
  ZIClass().u()
  ZICompanion.f()
  ZICompanion.g()
  ZICompanion().u()
  ZICompanionInheritance.f()
  ZICompanionInheritance.g()
  ZICompanionInheritance().u()
  trace eq """
    ZIClass.f() ZIClass.g()
    ZIOpen.f() ZIOpen.g()
    ZIOpen.f()
    ZICompanionInheritance.g()
    ZICompanionInheritance.h()
  """
}

ZICompanion uses a ZIOpen object as its companion object, and ZICompanionInheritance creates a ZIOpen object while overriding and extending ZIOpen. ZIClass shows that you can implement an interface while creating the companion object.

If the class you want to use as a companion object is not open, you cannot use it directly as we did above. However, if that class implements an interface you can still use it via [Class Delegation](javascript:void(0)):

// CompanionObjects/CompanionDelegation.kt
package companionobjects
import atomictest.*

class ZIClosed : ZI {
  override fun f() = "ZIClosed.f()"
  override fun g() = "ZIClosed.g()"
}

class ZIDelegation {
  companion object: ZI by ZIClosed()
  fun u() = trace("${f()} ${g()}")
}

class ZIDelegationInheritance {
  companion object: ZI by ZIClosed() {
    override fun g() =
      "ZIDelegationInheritance.g()"
    fun h() =
      "ZIDelegationInheritance.h()"
  }
  fun u() = trace("${f()} ${g()} ${h()}")
}

fun main() {
  ZIDelegation.f()
  ZIDelegation.g()
  ZIDelegation().u()
  ZIDelegationInheritance.f()
  ZIDelegationInheritance.g()
  ZIDelegationInheritance().u()
  trace eq """
    ZIClosed.f() ZIClosed.g()
    ZIClosed.f()
    ZIDelegationInheritance.g()
    ZIDelegationInheritance.h()
  """
}

ZIDelegationInheritance shows that you can take the non-open class ZIClosed, delegate it, then override and extend that delegate. Delegation forwards the methods of an interface to the instance that provides an implementation. Even if the class of that instance is final, we can still override and add methods to the delegation receiver.

Here’s a small brain-teaser:

// CompanionObjects/DelegateAndExtend.kt
package companionobjects
import atomictest.eq

interface Extended: ZI {
  fun u(): String
}

class Extend : ZI by Companion, Extended {
  companion object: ZI {
    override fun f() = "Extend.f()"
    override fun g() = "Extend.g()"
  }
  override fun u() = "${f()} ${g()}"
}

private fun test(e: Extended): String {
  e.f()
  e.g()
  return e.u()
}

fun main() {
  test(Extend()) eq "Extend.f() Extend.g()"
}

In Extend, the ZI interface is implemented using its own companion object, which has the default name Companion. But we are also implementing the Extended interface, which is the ZI interface plus an extra function u(). The ZI portion of Extended is already implemented, via Companion, so we only need to override the additional function u() to complete Extend. Now an Extend object can be upcast to Extended as the argument to test().

A common use for a companion object is controlling object creation—this is the Factory Method pattern. Suppose you’d like to only allow the creation of Lists of Numbered2 objects, and not individual Numbered2 objects:

// CompanionObjects/CompanionFactory.kt
package companionobjects
import atomictest.eq

class Numbered2
private constructor(private val id: Int) {
  override fun toString(): String = "#$id"
  companion object Factory {
    fun create(size: Int) =
      List(size) { Numbered2(it) }
  }
}

fun main() {
  Numbered2.create(0) eq "[]"
  Numbered2.create(5) eq
    "[#0, #1, #2, #3, #4]"
}

The Numbered2 constructor is private. This means there’s only one way to create an instance—via the create() factory function. A factory function can sometimes solve problems that regular constructors cannot.

Constructors in companion objects are initialized when the enclosing class is instantiated for the first time in a program:

// CompanionObjects/Initialization.kt
package companionobjects
import atomictest.*

class CompanionInit {
  companion object {
    init {
      trace("Companion Constructor")
    }
  }
}

fun main() {
  trace("Before")
  CompanionInit()
  trace("After 1")
  CompanionInit()
  trace("After 2")
  CompanionInit()
  trace("After 3")
  trace eq """
    Before
    Companion Constructor
    After 1
    After 2
    After 3
  """
}

You can see from the output that the companion object is constructed only once, the first time a CompanionInit() object is created.

Exercises and solutions can be found at www.AtomicKotlin.com.