I'm trying to use the invoke function with objects...
# announcements
s
I'm trying to use the invoke function with objects that should be singletons, basically for having retrofit accept different base urls. If I call invoke("some url") in different places of the app how does that affect the singleton creation? Do I get the same object with the changed parameter , or is it creating a new object every time I call invoke?
k
What are these "objects that should be singletons"? Are they Kotlin
object {}
things with an
operator fun invoke
?
s
@karelpeeters yes exactly that
k
If you just have a top level
object
then it'll be a singleton, and using that object in multiple places shouldn't be a problem, there will only be a single instance.
(Unless there's reflection or serialization going on, that can break the singleton guarantee)
s
No, not using reflection or serialization. Ok. It'll be a singleton even if I call invoke() with different parameters in multiple places?
I've been reading this, wonder if I need to write some code like this https://medium.com/@BladeCoder/kotlin-singletons-with-argument-194ef06edd9e
k
There's nothing special about
invoke
in any way, it's just a normal function. I don't understand where the confusion comes from:
Copy code
object Test {
    fun foo() {
        println("I'm $this")
    }
}
Of course it's the same singleton every time, and it's the same for
invoke
.
That blog post is for when you want a singleton that needs to be initialized, but that's not the usual case.
s
Copy code
object ApiController2 {

    private var baseUrl: String = "<https://jsonplaceholder.typicode.com/>"

    operator fun invoke(baseUrl: String?): AppAPI {
        if (baseUrl != null) this.baseUrl = baseUrl
        return controller
    }

    operator fun invoke(): AppAPI {
        return controller
    }

    private val dispatcher: Dispatcher by lazy { Dispatcher() }

    private val controller: AppAPI by lazy {

        dispatcher.maxRequests = 64

        val okHttpClient = OkHttpClient
            .Builder()
            .dispatcher(dispatcher)
            .connectionPool(ConnectionPool())
            .build()

        Retrofit.Builder()
            .baseUrl(baseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .client(okHttpClient)
            .build()
            .create(AppAPI::class.java)
    }

}
yes indeed it always returns the same object
k
That's a strange setup, having the
lazy
creation be influenced only by the first call to
invoke
.
If you really want this then I'd do what the blogpost says instead.
But I think these fake singletons are a bad idea, just pass actual instances around.
s
it's a fake singleton?.. I'm just curious about the inner workings of this and in the future implement the best solution.
yep that lazy int the controller might be useless
k
ApiController2
is a real singleton, but you're using it to create a controller in a strange way, where the first call
invoke(url1)
creates a controller, all future calls
invoke(url1)
silently ignore the url parameter and just return the previously created object.
What inner workings do you want to know about? It's just a combination of
object
, the property delegate
lazy
and operator overloading
invoke
.
👌 1
s
all inner workings 🙂
k
Well that's a lot to type out in a slack comment simple smile
s
thanks
😀