Effective Kotlin Item 48: Consider using object declarations
When you have a class without any instance-specific state, you can turn it into an object declaration to define a singleton. This means not defining a constructor and using the object
keyword instead of class
. We reference the singleton object using the name of the object declaration.
object Singleton {
fun doSomething() {
// ...
}
}
fun main() {
val obj = Singleton
obj.doSomething()
Singleton.doSomething()
}
Object declarations are useful to limit the number of created objects. This is especially useful for classes that are created many times in your projects, like events or markers. Thanks to object declarations, we can be sure that they have only one instance.
sealed class ValueChange<out T>
data object Keep : ValueChange<Nothing>()
data object SetDefault : ValueChange<Nothing>()
data object SetEmpty : ValueChange<Nothing>()
data class Set<out T>(val value: T) : ValueChange<T>()
sealed class ManagerMessage
data class CodeProduced(val code: String) : ManagerMessage()
data object ProductionStopped : ManagerMessage()
sealed interface AdView
data object FacebookAd : AdView
data object GoogleAd : AdView
data class OwnAd(val text: String,val imgUrl: String):AdView
It’s a bit more challenging when you want to turn a class that has some generic parameter types, like DeleteAll
in the following example, into an object declaration:
sealed interface StoreMessage<T>
data class Save<T>(val data: T) : StoreMessage<T>
data class DeleteAll<T> : StoreMessage<T>
In such cases, it is popular to use the pattern called Covariant Nothing Object36. To use it, we need to make the type parameter of the supertype class covariant (so, use the out
modifier next to T
in the StoreMessage
declaration), then use Nothing
as a type argument for the object declaration:
sealed interface StoreMessage<out T>
data class Save<T>(val data: T) : StoreMessage<T>
data object DeleteAll : StoreMessage<Nothing>
Since Nothing
is a subtype of all types in Kotlin, and T
in StoreMessage
is covariant, StoreMessage<Nothing>
is a subtype of all StoreMessage<T>
types. This means that DeleteAll
is a subtype of StoreMessage<T>
for all T
types.
val deleteAllInt: StoreMessage<Int> = DeleteAll
val deleteAllString: StoreMessage<String> = DeleteAll
This pattern is used in many projects and libraries, including Kotlin stdlib. For instance, EmptyList
is an object declaration that is a subtype of List<Nothing>
; as a result, it is a subtype of all List<T>
types. This way, there is only one instance of an empty list in the whole application.
internal object EmptyList : List<Nothing> {
// ...
}
val emptyListInt: List<Int> = EmptyList
val emptyListString: List<String> = EmptyList
Summary
- To define singletons, turn classes without an instance-specific state into object declarations.
- Use the covariant nothing object pattern to turn classes with generic type parameters into object declarations.
Marcin Moskala is a highly experienced developer and Kotlin instructor as the founder of Kt. Academy, an official JetBrains partner specializing in Kotlin training, Google Developers Expert, known for his significant contributions to the Kotlin community. Moskala is the author of several widely recognized books, including "Effective Kotlin," "Kotlin Coroutines," "Functional Kotlin," "Advanced Kotlin," "Kotlin Essentials," and "Android Development with Kotlin."
Beyond his literary achievements, Moskala is the author of the largest Medium publication dedicated to Kotlin. As a respected speaker, he has been invited to share his insights at numerous programming conferences, including events such as Droidcon and the prestigious Kotlin Conf, the premier conference dedicated to the Kotlin programming language.
Owen has been developing software since the mid 1990s and remembers the productivity of languages such as Clipper and Borland Delphi.
Since 2001, He moved to Web, Server based Java and the Open Source revolution.
With many years of commercial Java experience, He picked up on Kotlin in early 2015.
After taking detours into Clojure and Scala, like Goldilocks, He thinks Kotlin is just right and tastes the best.
Owen enthusiastically helps Kotlin developers continue to succeed.
Nicola Corti is a Google Developer Expert for Kotlin. He has been working with the language since before version 1.0 and he is the maintainer of several open-source libraries and tools.
He's currently working as Android Infrastructure Engineer at Spotify in Stockholm, Sweden.
Furthermore, he is an active member of the developer community.
His involvement goes from speaking at international conferences about Mobile development to leading communities across Europe (GDG Pisa, KUG Hamburg, GDG Sthlm Android).
In his free time, he also loves baking, photography, and running.
Emanuele is passionate about Android and has been fascinated by it since 2010: the more he learns, the more he wishes to share what he knows with others, which is why he started maintaining his own blog.
In his current role as Senior Android Developer at Mozio, he is now focusing on Kotlin Multiplatform Mobile: he has already given a couple of talks on this topic on various occasions, so far.