What is a companion object?
Companion object is an object accompanying the class, independent of the class instances. Thus, companion objects are used to bring in the static essence — to enable accessing properties and functions of a class that are common across instances.
companion object brings in the static essence, we don't need to use a companion object everywhere where we would have used a static variable. Kotlin's
companion object is not a two word replacement for Java's
Consider two most common use cases of
static - creating constants, and for "util" classes.
If we use a companion object for these, like -
Let’s decompile this and see what it looks like -
We see that the use of
companion object decompiles to using an inner class called
Companion. Is this what you were really going for? Do you want to create a nested class with all the hullabaloo, only to create static constants and functions?
companion object brings in the static essence, no doubt. But, it is not the only way to do so.
Consider this alternate approach of using top-level properties/functions -
Decompiling this, we see -
We see that using top-level construct here decompiles to far simpler code, without the overhead of creating inner classes, yet retaining the static essence.
If you want to group a bunch of constants together, you can also use a singleton
object , like -
This depends on what you are trying to achieve. It may be good to use objects to group constants like error strings, etc; on the other hand, when constants are used heavily in a single file, it’s good to declare these as top-level properties in the file, followed by other code, keeping it easier to reason about code.
Most often when we think we need a companion object, actually, we may not. Reiterating what we looked at in the beginning of this article -
Companion object is an object accompanying the class.
Thus, use a companion object only when its contents are whole only with the rest of the class; otherwise, the overhead is largely unwarranted, and the code is unidiomatic. For the most common static use-cases like creating constants, or functions in “util” files that operate referentially transparently on the input, it is best to create top-level constructs, grouping them in files (or objects, if reasonable) by content relevancy and project code structure.
Also published on supriyasrivatsa.com