Companion object instead of static


#1

What are reasons to have companion object instead of static block with methods and variables?
What are use cases of companion object what can not be implemented with static?

https://kotlinlang.org/docs/reference/object-declarations.html#companion-objects
This is example with Factory
But the same can be achieved by MyClass implementing Factory interface


#2

A companion object is an actual object instead of just a loose set of functions and fields within a specific scope. This allows interface implementation, assignment to variables, etc.


#3

This allows interface implementation, assignment to variables, etc

can you please show some examples when this feature should be used and it can not be done with static?


#4

To avoid repeating the arguments, for and against, companion objects, can I just say that this was discussed ad nauseam in this thread.

The only thing I would add is that the Kotlin design team seem to be split over this issue and one prominent team member recently stated publicly that, if Kotlin were to reach version 2.0 (thereby allowing non-backwards compatible changes), he would get rid of companion objects and replace them with static members.

Personally, I would prefer to see both being supported as getting rid of companion objects now would be a huge breaking change and they do have some features which ‘normal’ static members lack.


#5

But we can have both, static members and simple/named object, without companion.


#6

Yes, but unlike ordinary objects within classes, members of companion objects can be called just by prefixing them with the class name.


#7

Personally I don’t use companions as objects a lot, but here is a contrived example:

interface DataTypeConverterFactory {
  fun getDisplayName(locale: Locale): String
  val inputType: String
  val outputType: String
  fun create(): DataTypeConverter
}

class StringToIntConverter : DataTypeConverter {
   // ...

   companion object : DataTypeConverterFactory {
       override fun getDisplayName(locale: Locale) = "[needs localization] String to int"
       override val inputType = "String"
       override val outputType = "Int"
       override fun create() = StringToIntConverter()
   }
}

val availableConverters = listOf(StringToIntConverter.Companion)

fun main(args: Array<String>) {
    println("Available converters:")
    availableConverters.forEach {
        println("${it.getDisplayName(Locale.ENGLISH)} (${it.inputType} -> ${it.outputType})")
    }
}

#8

But you do not need a companion object we can use simply an object

    class StringToIntConverter : DataTypeConverter {
       // ...

       object Factory : DataTypeConverterFactory {

#9

But, if you did that, you’d need to create an instance of StringToIntConverter to access the Factory object.


#10

Yes, but this is case for static members :slight_smile:


#11

Correct, companion simply indicates that is more closely tied to the enclosing class. And it defines a convention for the name of an object shared by all instances of a class: Companion.

I would use a companion in most cases: shared constants, and “static” fields and functions. I would use other objects for implementations of external interfaces that can be shared by all instances of the class, and I would make these objects private. But this is definitely not a hard rule, best practice, …

You do not have to use a companion if you think it does not add any value. Designs with or without will work equally well.


#12

This is not correct. Objects defined at the class level are not members of instances. This results in a compilation error:

class StringToIntConverter {
   object Factory {
       val y = "The factory"
   }
}

fun main(args: Array<String>) {
    val x = StringToIntConverter()
    println(x.Factory.y)
}

#13

Apologies, you’re right of course.


#14

So do you agree that if there was only static members and simply(not companion) objects this will be enough?


#15

No, it will not be enough. Because I might want to store the object somewhere, or have it implement an interface.

If you are here to argue for static members, I am going to stop with this discussion. As @alanfo pointed out, this has already been discussed at length.

If you are interested in how to design a solution in the Kotlin way, and have more questions, do ask them and I will help as best as I can.


#16

I too hope static fields and methods will be added to Kotlin someday. Companion objects don’t seem to have (in practice) much use except to mimic statics, albeit less efficiently. I’ve read both sides of the debate on this topic and feel Kotlin got it wrong on this one: statics get the job done without the overhead, both runtime and code noise.