The Amazing "static" world in Kotlin and how it fits Singletons

Pedro Alvarez
4 min readSep 11, 2023

--

Image from https://wallpapersafari.com/w/27RL4C

You may be wondering what exactly I am calling as a static world in this header. Well, that's the way I am expressing how impressed I am with the way Kotlin isolates everything that is static inside a scope and making it as a separated object that is not actually an instance of anything(or you can think as it was a very special instance). One of the things I most enjoyed in Kotlin is the way Singletons are totally embeded in the language and you don't need to insert any boiler code into your classes

What are Singletons

Singletons are maybe the most polemic design pattern in software development as most people in the community will recommend avoiding its use no matter the programming language you are adopting. That's because they introduce a problem that actually has a turnaround when you are dealing with unit tests. But let's get back to the definition:

Singleton is a pattern that allows you to make some class to be instantiated just once in the entire application. You can achieve that in most languages in the following way:

  1. Make your constructor as private
  2. Provide a static instance of your class in its own definition

Please take a look in this Java code that implements the Singleton in the former way:

As you can see, we have some boiler plate that requires you to implement the initializer of your class even when it doesn't take any argument and doesn't do anything.

The turnaround for making any class that depends on it to be testable is just creating an interface to your NetworkService and make it conform to it:

Then your service may be injected in another class as an interface even as a singleton, because what matters is the interface type, which can be mocked:

Usually Singletons are used for classes that don't make sense to contain more than one instance, like service managers, facades, dependency containers and permission managers. If you want to customize the use cases for a singleton, you can inject parameters as arguments to your methods, instead of creating properties for each of them.

Objects in Kotlin

Kotlin introduces a new keyword called object , which actually corresponds to a class, but not any usual class. This one is a specific instance that has its own implementation, parameters and methods, however, this is the only instance of the type, being the type itself the instance at the same time. This is the built-in Singleton in Kotlin:

Look how this singleton is much less verbose than the original ones. The object in Kotlin may also conform to interfaces as any other type:

This way allows any consumer that relies on your service to be unit-testable. However, there is only one thing that doesn't please my eyes:

Take a look in the way I am initializing the consumer

When you are calling your object, necessarily the name is the same type of it, which in my opinion, leads to confusion. Kotlin could provide some mechanism to retrieve the object instance as something like NetworkService.instance .

Introducing the "static world" to non-Singleton objects: Companion objects

When we have other sorts of objects that are classes in fact(not singletons), we sometimes desire some intrinsic features that belong to the class itself, instead of relying on an instance. Take a look in this example(in Java again):

Here we have a class that is not a Singleton, since its constructor can be accessed multiple times. However, this class has some members that are static and don't belong to the case of an individual object.

In Kotlin, this is made with a much cleaner approach that allows you to isolate the static scope from the instance(or usual) one. Basically, you have an object that actually belongs to the scope of your class and allows you to declare members as static in your class(You can think as the class was a half-singleton, but I don't trust this definition since you can in fact instantiate the class multiple times):

The companion object separates the static part of your class from the instance level one, therefore allowing you to insert functions and variables that are not related to the instance level, but are still related to your PermissionManager scope

Nested singletons with companion objects

By default, your companion object is anonymous and each of its members may be accessed directly from your parent class:

However, you can in fact define a name to your companion object . That is amazing, because you can define a named nested scope to your class.

One important detail is that each class can only have one companion object , which means you cannot define multiple "static scopes" in your classes. However, it doesn't block you from creating multiple standard objects in your class:

The biggest difference between the two types of object is that the companion object belongs to its class lifecycle and is initialized once the class is. Nested objects have lazy evaluation and are only instantiated when they are called.

Conclusion

This article provided an overview about the fantastic way Kotlin provides the implementation of static members of a class and how the Singleton pattern perfectly fits Android development. With that in mind, you can easily separate what is static from what is in the instance level. We also differentiated the concept of nested objects, which in fact are separated types that only exist in a class scope. I hope you enjoyed ;)

--

--

Pedro Alvarez
Pedro Alvarez

Written by Pedro Alvarez

Mobile Engineer | iOS | Android | KMP | Flutter | WWDC19 scholarship winner | Blockchain enthusiast https://www.linkedin.com/in/pedro-alvarez94/

No responses yet