== Why is this an issue?

In Kotlin, object declarations and object expressions are the designed way to implement
the singleton pattern.
Because this is a built-in language feature, it should be used
as an idiom instead of resorting to custom idioms.

An alternative is to declare private constructors
and to provide a single class instance within a companion object.
However, this idiom is adopted from other languages like Java which do not feature
the direct declaration of objects. It should not be used in Kotlin.

=== What is the potential impact?

==== Readability and Understanding

This change makes it easier to understand the code
because this is how singletons are intended to be used in Kotlin.
When developers share common standards and idioms, they need to spend less effort on understanding each other's code.

==== Code Redundancy

Using a built-in language feature or a standard API is always better than a custom implementation,
because the reimplementation of something that already exists is unnecessary.

== How to fix it

Remove the private constructor of the class and
remove the companion object or the variable that provides the single instance from the class.
Replace the class declaration with an object declaration if a name is required for the singleton.
Replace the class declaration with an object expression if the singleton instance can be anonymous.

=== Code examples

==== Noncompliant code example

[source,kotlin,diff-id=1,diff-type=noncompliant]
----
class DeviceManager private constructor() {
    fun instanceMethod() {
        // ...
    }

    companion object { // Noncompliant, explicit class instance provided
        val instance = DeviceManager()
    }
}
----

==== Compliant solution

[source,kotlin,diff-id=1,diff-type=compliant]
----
object DeviceManager { // Compliant, object declaration used
    fun instanceMethod() {
        // ...
    }
}
----

==== Noncompliant code example

[source,kotlin]
----
interface LayoutStrategy {
    val instanceProperty: String
    fun instanceMethod()
}
----

[source,kotlin,diff-id=2,diff-type=noncompliant]
----
class CustomLayoutStrategy private constructor(): LayoutStrategy  {

    override val instanceProperty = "Hello, world!"

    override fun instanceMethod() {
        // ...
    }

    companion object { // Noncompliant, explicit class instance provided
        private val instance by lazy {
            CustomLayoutStrategy()
        }

        fun getInstance(): LayoutStrategy = instance
    }
}

fun createUI() {
    val component = Container()
    component.setLayoutStrategy(CustomLayoutStrategy.getInstance())
}
----

==== Compliant solution

[source,kotlin,diff-id=2,diff-type=compliant]
----
fun createUI() {
    val component = Container()
    component.setLayoutStrategy(object: LayoutStrategy { // Compliant, object expression used

        override val instanceProperty = "Hello, world!"

        override fun instanceMethod() {
            // ...
        }
    })
}
----

== Resources

=== Documentation

* https://kotlinlang.org/docs/object-declarations.html[Kotlin Docs, Object expressions and declarations]

=== Articles & blog posts

* https://in-kotlin.com/design-patterns/singleton[In Kotlin, Singleton class / Object class / Companion object]