The documentation for companion objects has the following example
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
Here Factory is the name of the companion object. It then goes on to say:
The name of the companion object can be omitted, in which case the name Companion will be used:
However there is no example that I can see that uses the name of the companion object.
Since you can only have one companion object per class (otherwise you get a Only one companion object is allowed per class error) the name feels like some pretty useless syntactic sugar to me.
What can the name of the companion object actually be used for?
Why would one bother to use any name for it?
You can use the name of the companion like:
MyClass.create() // not via companion name
MyClass.Companion.create() // via default companion name
MyClass.Factory.create() // via companion name
The name is maybe not that important for Kotlin, because you can just access the method without knowing that there is a companion object (line one above). It is more like a personal style, if you want to make the access to such functions more explicit.
But for java interop it makes a difference, because you have to access the function via the companion name:
MyClass.Factory.create(); // with named companion
MyClass.Companion.create(); // with unnamed comanion
Well, companion objects in Kotlin are not just syntactic sugar. They are actually a type. They are able to do much more thing, and need not to be see as just replacement of static.
You can actually extend class or implement an interface. See an example below.
open class Super {
open fun sayHello() {
println("Hello")
}
}
class Some {
companion object Child : Super() {
override fun sayHello() {
super.sayHello()
println("Hello from companion object")
}
}
}
fun main() {
Some.Child.sayHello()
}
If you do not use an explicit name, the companions name is Companion, thus it can be omitted, like you already quoted.
Sometimes you may want to have an explicit name in your calls, which would be MyClass.Factory.create() in your example. For namespace reasons maybe.
I don't see a many reasons to name a companion object, either. Except if you care about Java interop with your Kotlin code. Then, you need to explicitly write the companions name.
Another reason you might care about the name is, when you define an extension function on it:
fun MyClass.Companion.ext() = "myext"
In this case, it can be clearer when it has a name like Factory, on which specific factory methods are added via extension.
However there is no example that I can see that uses the name of the companion object.
class Person(val name: String) { companion object Loader {
fun fromJSON(jsonText: String): Person = ... }
}
>>> person = Person.Loader.fromJSON("{name: 'Dmitry'}") >>> person.name
Dmitry
>>> person2 = Person.fromJSON("{name: 'Brent'}") >>> person2.name
Brent
Related
I'm trying to create a Map that contains generic-parameterized types. For example:
abstract class Foo {
companion object {
val fooInjectors = HashMap<Class<T: Foo>, Injector<T: Foo>>()
}
}
The idea is to have fooInjectors (which would be static in Java or in a companion object in Kotlin) contain a cache of sub-classes of Foo and their corresponding Injector.
Unfortunately, I can't get this to compile. I'd very much appreciate it if someone would help me figure out the syntax for this!
As far as I know, you are trying to do something that is impossible in Kotlin. The companion object is a singleton and it doesn't make sense to generify a singleton as there will not be any further objects created hence generic types are irrelevant. So you can't generify the property you declared because it's in the companion object.
However, one way you could make this working is using a backing function. This backing function should annotate with declaration-site variance.
This simply means we tell the compiler that we only return a type T from the method (and don't consume). That allows us to use subtypes and the supertype of the T if required. This is called covariance.
You can look at the docs to understand it further - https://kotlinlang.org/docs/reference/generics.html#declaration-site-variance
Here's what I meant.
interface Injector<T>
class InjectorImpl<T> : Injector<T>
abstract class Foo {
companion object {
val fooInjectors = createMap<Foo>()
private fun <T> createMap(): HashMap<Class<out T>, Injector<out T>> {
return HashMap()
}
}
}
class Bar: Foo()
object Runner {
#JvmStatic
fun main(args: Array<String>) {
Foo.fooInjectors[Bar::class.java] = InjectorImpl<Bar>()
Foo.fooInjectors[Foo::class.java] = InjectorImpl<Bar>()
}
}
I am reading the Kotlin in Action book and trying to understand Companion Objects better, are there any other uses for Companion Ojbects other than adding method implementations from an interface/abstract class?
I came across a way of instantiating an object which only works if the class is abstract:
fun main(args: Array<String>) {
Fruit.showColor()
}
class Fruit(val name: String) {
companion object : Apple()
}
abstract class Apple {
fun showColor(){
print("I am an apple")
};
}
My mental model for companion object is language level support for safe singletons. i.e. instead of static methods on a class for Factory or Util methods, you can provide those related methods on the Singleton companion object.
The Companion status gives you a lot of default scoping wins that are similar to the java class with static methods.
Your example seems invalid, because why is the Fruit "singleton" an Apple?
I thought typealiases were the same as the original type, just a different name.
I figure typealiases have the same references as the original type.
typealias Celsius = Double
fun Double.Companion.foo() {} // Works
fun Celsius.Companion.foo() {} // Does not work
Here, Companion is accessible from Double but Celsius gives an unresolved reference error.
No, you can't access to the companion objects via typealias. One possible workaround to create one more typealias for concrete companion:
typealias CelsiusCompanion = Double.Companion
After that you can use it as following:
fun CelsiusCompanion.foo() {}
If you want to define an extension function, it is not possible as hluhovskyi already stated, but things are differently if you just want to invoke functions of a companion object.
There are two ways of accessing functions and properties within a companion object. You can either specify the access explicitely or implicitely. The implicit way works with a typealias the explicit one does not.
Consider this minimal example:
class ClassWithCompanion{
companion object {
fun sayHello() {
println("Hello")
}
}
}
typealias Alias = ClassWithCompanion
fun main(args: Array<String>) {
ClassWithCompanion.sayHello() // implicit
ClassWithCompanion.Companion.sayHello() // explicit
Alias.sayHello() // implicit (works)
Alias.Companion.test() // explicit (does not work)
}
What is the intended meaning of "companion object"? So far I have been using it just to replace Java's static when I need it.
I am confused with:
Why is it called "companion"?
Does it mean that to create multiple static properties, I have to group it together inside companion object block?
To instantly create a singleton instance that is scoped to a class, I often write
:
companion object {
val singleton by lazy { ... }
}
which seems like an unidiomatic way of doing it. What's the better way?
What is the intended meaning of "companion object"? Why is it called "companion"?
First, Kotlin doesn't use the Java concept of static members because Kotlin has its own concept of objects for describing properties and functions connected with singleton state, and Java static part of a class can be elegantly expressed in terms of singleton: it's a singleton object that can be called by the class' name. Hence the naming: it's an object that comes with a class.
Its name used to be class object and default object, but then it got renamed to companion object which is more clear and is also consistent with Scala companion objects.
Apart from naming, it is more powerful than Java static members: it can extend classes and interfaces, and you can reference and pass it around just like other objects.
Does it mean that to create multiple static properties, I have to group it together inside companion object block?
Yes, that's the idiomatic way. Or you can even group them in non-companion objects by their meaning:
class MyClass {
object IO {
fun makeSomethingWithIO() { /* ... */ }
}
object Factory {
fun createSomething() { /* ... */ }
}
}
To instantly create a singleton instance that is scoped to a class, I often write /*...*/ which seems like an unidiomatic way of doing it. What's the better way?
It depends on what you need in each particular case. Your code suits well for storing state bound to a class which is initialized upon the first call to it.
If you don't need it to be connected with a class, just use object declaration:
object Foo {
val something by lazy { ... }
}
You can also remove lazy { ... } delegation to make the property initialize on first class' usage, just like Java static initializers
You might also find useful ways of initializing singleton state.
Why is it called "companion"?
This object is a companion of the instances.
IIRC there was lengthy discussion here: upcoming-change-class-objects-rethought
Does it mean that to create multiple static properties, I have to group it together inside companion object block?
Yes. Every "static" property/method needs to be placed inside this companion.
To instantly create a singleton instance that is scoped to a class, I often write
You do not create the singleton instance instantly. It is created when accessing singleton for the first time.
which seems like an unidiomatic way of doing it. What's the better way?
Rather go with object Singleton { } to define a singleton-class. See: Object Declarations
You do not have to create an instance of Singleton, just use it like that Singleton.doWork()
Just keep in mind that Kotlin offers other stuff to organize your code. There are now alternatives to simple static functions e.g. you could use Top-Level-Functions instead.
When the classes/objects with related functionalities belong together, they are like companions of each other. A companion means a partner or an associate, in this case.
Reasons for companionship
Cleaner top-level namespace
When some independent function is intended to be used with some specific class only, instead of defining it as a top-level function, we define it in that particular class. This prevents the pollution of top-level namespace and helps with more relevant auto-completion hints by IDE.
Packaging convenience
It's convenient to keep the classes/objects together when they are closely related to each other in terms of the functionality they offer to each other. We save the effort of keeping them in different files and tracking the association between them.
Code readability
Just by looking at the companionship, you get to know that this object provides helper functionality to the outer class and may not be used in any other contexts. Because if it was to be used with other classes, it would be a separate top level class or object or function.
Primary purpose of companion object
Problem: companion class
Let's have a look at the kinds of problems the companion objects solve. We'll take a simple real world example. Say we have a class User to represent a user in our app:
data class User(val id: String, val name: String)
And an interface for the data access object UserDao to add or remove the User from the database:
interface UserDao {
fun add(user: User)
fun remove(id: String)
}
Now since the functionalities of the User and implementation of the UserDao are logically related to each other, we may decide to group them together:
data class User(val id: String, val name: String) {
class UserAccess : UserDao {
override fun add(user: User) { }
override fun remove(id: String) { }
}
}
Usage:
fun main() {
val john = User("34", "John")
val userAccess = User.UserAccess()
userAccess.add(john)
}
While this is a good setup, there are several problems in it:
We have an extra step of creating the UserAccess object before we can add/remove a User.
Multiple instances of the UserAccess can be created which we don't want. We just want one data access object (singleton) for User in the entire application.
There is a possibility of the UserAccess class to be used with or extended with other classes. So, it doesn't make our intent clear of exactly what we want to do.
The naming userAccess.add() or userAccess.addUser() doesn't seem very elegant. We would prefer something like User.add().
Solution: companion object
In the User class, we just replace the two words class UserAccess with the two other words companion object and it's done! All the problems mentioned above have been solved suddenly:
data class User(val id: String, val name: String) {
companion object : UserDao {
override fun add(user: User) { }
override fun remove(id: String) { }
}
}
Usage:
fun main() {
val john = User("34", "John")
User.add(john)
}
The ability to extend interfaces and classes is one of the features that sets the companion objects apart from Java's static functionality. Also, companions are objects, we can pass them around to the functions and assign them to variables just like all the other objects in Kotlin. We can pass them to the functions that accept those interfaces and classes and take advantage of the polymorphism.
companion object for compile-time const
When the compile-time constants are closely associated with the class, they can be defined inside the companion object.
data class User(val id: String, val name: String) {
companion object {
const val DEFAULT_NAME = "Guest"
const val MIN_AGE = 16
}
}
This is the kind of grouping you have mentioned in the question. This way we prevent the top-level namespace from polluting with the unrelated constants.
companion object with lazy { }
The lazy { } construct is not necessary to get a singleton. A companion object is by default a singleton, the object is initialized only once and it is thread safe. It is initialized when its corresponding class is loaded. Use lazy { } when you want to defer the initialization of the member of the companion object or when you have multiple members that you want to be initialized only on their first use, one by one:
data class User(val id: Long, val name: String) {
companion object {
val list by lazy {
print("Fetching user list...")
listOf("John", "Jane")
}
val settings by lazy {
print("Fetching settings...")
mapOf("Dark Theme" to "On", "Auto Backup" to "On")
}
}
}
In this code, fetching the list and settings are costly operations. So, we use lazy { } construct to initialize them only when they are actually required and first called, not all at once.
Usage:
fun main() {
println(User.list) // Fetching user list...[John, Jane]
println(User.list) // [John, Jane]
println(User.settings) // Fetching settings...{Dark Theme=On, Auto Backup=On}
println(User.settings) // {Dark Theme=On, Auto Backup=On}
}
The fetching statements will be executed only on the first use.
companion object for factory functions
Companion objects are used for defining factory functions while keeping the constructor private. For example, the newInstance() factory function in the following snippet creates a user by generating the id automatically:
class User private constructor(val id: Long, val name: String) {
companion object {
private var currentId = 0L;
fun newInstance(name: String) = User(currentId++, name)
}
}
Usage:
val john = User.newInstance("John")
Notice how the constructor is kept private but the companion object has access to the constructor. This is useful when you want to provide multiple ways to create an object where the object construction process is complex.
In the code above, consistency of the next id generation is guaranteed because a companion object is a singleton, only one object will keep track of the id, there won't be any duplicate ids.
Also notice that companion objects can have properties (currentId in this case) to represent state.
companion object extension
Companion objects cannot be inherited but we can use extension functions to enhance their functionality:
fun User.Companion.isLoggedIn(id: String): Boolean { }
The default class name of the companion object is Companion, if you don't specify it.
Usage:
if (User.isLoggedIn("34")) { allowContent() }
This is useful for extending the functionality of the companion objects of third party library classes. Another advantage over Java's static members.
When to avoid companion object
Somewhat related members
When the functions/properties are not closely related but only somewhat related to a class, it is recommended that you use top-level functions/properties instead of companion object. And preferably define those functions before the class declaration in the same file as that of class:
fun getAllUsers() { }
fun getProfileFor(userId: String) { }
data class User(val id: String, val name: String)
Maintain single responsibility principle
When the functionality of the object is complicated or when the classes are big, you may want to separate them into individual classes. For example, You may need a separate class to represent a User and another class UserDao for database operations. A separate UserCredentials class for functions related to login. When you have a huge list of constants that are used in different places, you may want to group them in another separate class or file UserConstants. A different class UserSettings to represent settings. Yet another class UserFactory to create different instances of the User and so on.
That's it! Hope that helps make your code more idiomatic to Kotlin.
Why is it called "companion"?
An object declaration inside a class can be marked with the companion keyword:
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
Members of the companion object can be called by using simply the class name as the qualifier:
val instance = MyClass.create()
If you only use 'object' without 'companion', you have to do like this:
val instance = MyClass.Factory.create()
In my understanding, 'companion' means this object is companion with the outter class.
We can say that companion is same as "Static Block" like Java, But in case of Kotlin there is no Static Block concept, than companion comes into the frame.
How to define a companion block:
class Example {
companion object {
fun display(){
//place your code
}
}
}
Calling method of companion block, direct with class name
Example.Companion.display
While developing for android I sometimes come across something that looks like this:
var someModel: someViewModel by notNullAndObservable { vm ->
...
}
I don't understand what the significance of the by keyword is.
In simple words, you can understand by keyword as provided by.
From the perspective of property consumer, val is something that has getter (get) and var is something that has getter and setter (get, set). For each var property there is a default provider of get and set methods that we don't need to specify explicitly.
But, when using by keyword, you are stating that this getter/getter&setter is provided elsewhere (i.e. it's been delegated). It's provided by the function that comes after by.
So, instead of using this built-in get and set methods, you are delegating that job to some explicit function.
One very common example is the by lazy for lazy loading properties.
Also, if you are using dependency injection library like Koin, you'll see many properties defined like this:
var myRepository: MyRepository by inject() //inject is a function from Koin
In the class definition, it follows the same principle, it defines where some function is provided, but it can refer to any set of methods/properties, not just get and set.
class MyClass: SomeInterface by SomeImplementation, SomeOtherInterface
This code is saying:
'I am class MyClass and I offer functions of interface SomeInterface which are provided by SomeImplementation.
I'll implement SomeOtherInterface by myself (that's implicit, so no by there).'
In the Kotlin reference you will find two uses for by, the first being Delegated Properties which is the use you have above:
There are certain common kinds of properties, that, though we can implement them manually every time we need them, would be very nice to implement once and for all, and put into a library. Examples include lazy properties: the value gets computed only upon first access,
observable properties: listeners get notified about changes to this property,
storing properties in a map, not in separate field each.
Here you delegate the getter/setter to another class that does the work and can contain common code. As another example, some of the dependency injectors for Kotlin support this model by delegating the getter to receiving a value from a registry of instances managed by the dependency injection engine.
And Interface/Class delegation is the other use:
The Delegation pattern has proven to be a good alternative to implementation inheritance, and Kotlin supports it natively requiring zero boilerplate code. A class Derived can inherit from an interface Base and delegate all of its public methods to a specified object
Here you can delegate an interface to another implementation so the implementing class only needs to override what it wants to change, while the rest of the methods delegate back to a fuller implementation.
A live example would be the Klutter Readonly/Immutable collections where they really just delegate the specific collection interface to another class and then override anything that needs to be different in the readonly implementation. Saving a lot of work not having to manually delegate all of the other methods.
Both of these are covered by the Kotlin language reference, start there for base topics of the language.
The syntax is:
val/var <property name>: <Type> by <expression>.
The expression after by is the delegate
if we try to access the value of property p, in other words, if we call get() method of property p, the getValue() method of Delegate instance is invoked.
If we try to set the value of property p, in other words, if we call set() method of property p, the setValue() method of Delegate instance is invoked.
Delegation for property:
import kotlin.reflect.KProperty
class Delegate {
// for get() method, ref - a reference to the object from
// which property is read. prop - property
operator fun getValue(ref: Any?, prop: KProperty<*>) = "textA"
// for set() method, 'v' stores the assigned value
operator fun setValue(ref: Any?, prop: KProperty<*>, v: String) {
println("value = $v")
}
}
object SampleBy {
var s: String by Delegate() // delegation for property
#JvmStatic fun main(args: Array<String>) {
println(s)
s = "textB"
}
}
Result:
textA
value = textB
Delegation for class:
interface BaseInterface {
val value: String
fun f()
}
class ClassA: BaseInterface {
override val value = "property from ClassA"
override fun f() { println("fun from ClassA") }
}
// The ClassB can implement the BaseInterface by delegating all public
// members from the ClassA.
class ClassB(classA: BaseInterface): BaseInterface by classA {}
object SampleBy {
#JvmStatic fun main(args: Array<String>) {
val classB = ClassB(ClassA())
println(classB.value)
classB.f()
}
}
Result:
property from ClassA
fun from ClassA
Delegation for parameters:
// for val properties Map is used; for var MutableMap is used
class User(mapA: Map<String, Any?>, mapB: MutableMap<String, Any?>) {
val name: String by mapA
val age: Int by mapA
var address: String by mapB
var id: Long by mapB
}
object SampleBy {
#JvmStatic fun main(args: Array<String>) {
val user = User(mapOf("name" to "John", "age" to 30),
mutableMapOf("address" to "city, street", "id" to 5000L))
println("name: ${user.name}; age: ${user.age}; " +
"address: ${user.address}; id: ${user.id}")
}
}
Result:
name: John; age: 30; address: city, street; id: 5000