Please help why below code snippet throws `NullPoi...
# getting-started
p
Please help why below code snippet throws
NullPointerException
when calling
createInstance()
method. Is there any solution to make it work
Copy code
fun main() {
    val a = A.getInstance()
    println("value of ${a.num}")
}

class A {
    val num: Int = 10
    
    companion object : SingletonHolderWithoutArgs<A>(::createInstance) {
        private fun createInstance(): A {
            return A()
        }
    }
}

open class SingletonHolderWithoutArgs<out T>(private val func: () -> T) {

    @Volatile
    private var instance: T? = null

    fun getInstance(): T =
        synchronized(this) {
            instance ?: func().also { instance = it }
        }
}
s
I think what’s happening here is that you’re creating a bound reference to the
A.createInstance
function inside A’s constructor, i.e. before
A
has actually been initialised. Although A has been initialised by the time you call the function, the reference was created before that happened.
I’m not sure about this though 🤔 it’s confusing
l
some sort of convoluted Singleton-constructor pattern?
p
If i put
inline
keyword before
createInstance
method then problem is solved but I don't know why
inline
keyword fixes the problem.
s
That’s the cause of the NPE, though it doesn’t help you fix it. Why do you need your singleton creation to be so complicated? Does something prevent you just making
A
an
object
?
The normal way to make a singleton like that in Kotlin would just be
Copy code
fun main() {
    val a = A
    println("value of ${a.num}")
}

object A {
    val num: Int = 10
}
m
Even if you cannot make it an object, you could still easily just create one in the companion, it can even use the
lazy
delegate.
p
can you give me example
This is the class i'm trying to create.
Copy code
internal class Starter private constructor(
    initializer: Initializer,
    creator: Creator,
    unlocker: Unlocker
) : Initializer by initializer,
    Creator by creator,
    Unlocker by unlocker {

    companion object :
        SingletonHolderWithoutArgs<Starter>(Starter::createInstance) {

        private inline fun createInstance(): Starter {
            val job = Components.from(AComponent::class.java).Job()
            return Starter(
                SdkDataVaultInitializerImpl(job),
                SdkDataVaultCreatorImpl(job),
                SdkDataVaultUnlockerImpl(job)
            )
        }
    }
}
m
Copy code
class A {
    val num: Int = 10

    companion object {
        val instance by lazy { A() }
    }
}

fun main() {
    val a = A.instance
    println("value of ${a.num}")
}
Seems like you are just trying to make a lazy singleton, if so just declare
Starter
as an object class. Are these singleton holders are not needed (they weren't really need in Java either)
The
createInstance
function just becomes your
init
block.
p
Ok
If i replace
createInstance()
with
init
block then i'm making my class not easily testable right? What i mean is the
private constructor
can be
@VisibleForTesting constructor(...)
in future. So
init
block might give me trouble at that time.
In brief, I want to simplify my class construction process in production (i.e all objects needed for my class are instantiated inside the class. ) But this class should be easily testable (So want to expose a constructor that accepts all required parameters)
l
hmm, sounds like you need some dependency injection - it’s generally not considered a good idea for a class to instantiate its dependencies, as (like you’ve pointed out) it’s tricky to test, and it can be inflexible.
k
Btw
@Volatile
is useless