Kotlin Singletons: Object vs a Class with private constructor - kotlin

The sunflower example app by Google uses a private Class with a companion object to implement a Singleton pattern of their repository instead of simply implementing the repository as an (inherently Singleton) Object.
This is the first time I've seen a Singleton implemented this way in Kotlin instead of implementing it as an Object. In what context(s) should this private constructor implementation be used instead of the more common Object implementation?
class GardenPlantingRepository private constructor(
private val gardenPlantingDao: GardenPlantingDao
) {
suspend fun createGardenPlanting(plantId: String) {
withContext(IO) {
val gardenPlanting = GardenPlanting(plantId)
gardenPlantingDao.insertGardenPlanting(gardenPlanting)
}
}
suspend fun removeGardenPlanting(gardenPlanting: GardenPlanting) {
withContext(IO) {
gardenPlantingDao.deleteGardenPlanting(gardenPlanting)
}
}
fun getGardenPlantingForPlant(plantId: String) =
gardenPlantingDao.getGardenPlantingForPlant(plantId)
fun getGardenPlantings() = gardenPlantingDao.getGardenPlantings()
fun getPlantAndGardenPlantings() = gardenPlantingDao.getPlantAndGardenPlantings()
companion object {
// For Singleton instantiation
#Volatile private var instance: GardenPlantingRepository? = null
fun getInstance(gardenPlantingDao: GardenPlantingDao) =
instance ?: synchronized(this) {
instance ?: GardenPlantingRepository(gardenPlantingDao).also { instance = it }
}
}
}

Using an object is an issue if your singleton instance needs parameters, like in this case here, with GardenPlantingDao, as they cannot take constructor arguments. This comes up frequently on Android, as there's many cases where singletons requires a Context to operate.
You could still use an object in these cases, but it would either be unsafe or inconvenient:
The first option would be to provide it with its dependencies using a setter method before using any of its other methods. This would mean that every other method would have to check if the dependencies have been initialized, and probably throw exceptions in case they haven't, which leads to runtime problems.
Alternatively, you could require any dependencies as arguments to each method of the singleton, which is tedious at the call site.
Hence the "traditional" way of implementing a singleton with a private constructor and a factory method instead.

Related

MockK creating invalid objects using a private constructor

Given a wrapper class around a foreign pointer:
class CObject private constructor(private val _internalCPointer: Long) {
external fun doACThing()
companion object {
external fun allocate(): CObject
}
}
mockK is generating instances of this object where _internalCPointer is 0, leading to segfaults.
How can I tell mockK to use CObject.allocate instead of the constructor?
It turns out that mockk is unable to mock external methods. So instead I replaced the class with stub kotlin methods, and then I was able to mock it properly.
class CObject private constructor(private val _internalCPointer: Long) {
fun doACThing() = __jni_doACThing
private external fun __jni_doACThing()
...
}
I never did figure out how to mock the constructor, but at least CObject can now be used in a mock environment.

I know we cannot make a instance of interface but this dude make it . Is this right?

Here we return Api().userLogin(email,password) . Here Api() is a interface and can we make the instance of interface like this ??
class UserRepository {
suspend fun userLogin(username:String, password:String):Response<AuthResponse>
{
return Api().userLogin(username,password)
}
}
This is my Interface
interface Api {
#FormUrlEncoded
#POST("login")
suspend fun userLogin(
#Field("email")
username:String,
#Field("password")
password:String
):Response<AuthResponse>
companion object
{
operator fun invoke():Api
{
return Retrofit.Builder()
.baseUrl("https://api.simplifiedcoding.in/course-apis/mvvm/")
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(Api::class.java)
}
}
}
One of the operators we can overload in Kotlin is the invoke operator, which is called when we "call" an instance as though it's a function. For instance, we could define
class Foo {
operator fun invoke() {
println("Hi")
}
}
and then call this with
val myFoo = Foo()
myFoo() # Calls myFoo.invoke()
Now, you have correctly pointed out that interfaces don't have constructors. As such, Api() cannot be a constructor call. The name Api refers to an interface as well as its companion object, and we're calling invoke on the companion object. So Api() in your code is equivalent to Api.invoke(), a method call on the companion object Api which, based on the code you've shown, uses Retrofit.Builder() to construct a concrete instance of the Api interface.

Is there a cleaner way to set a top-level variable later in code without making it a lateinit var?

So what I want to achieve is that to have the top-level variable set some time later in the main function, but I don't want to make it a lateinit var which certainly breaks the Extension variable functionality.
For instance this code doesn't work since extension variables don't support lateinit modifier:
lateinit var Dispatchers.Konvironment: MainCoroutineDispatcher
private set
fun main() {
...
Dispatchers.Konvironment = ArbitraryMainDispatcher(Thread.currentThread()) { queue.add(it) }
...
}
So what I finally came up with is to use a dummy variable and implement the getter of the val variable.
val Dispatchers.Konvironment: MainCoroutineDispatcher
get() = dispatcher
private lateinit var dispatcher: MainCoroutineDispatcher
fun main() {
...
dispatcher = ArbitraryMainDispatcher(Thread.currentThread()) { queue.add(it) }
...
}
But it is certainly not clean way to do that. It looks ugly (ish) creating multiple variable in the top-level structure is not very clean architecture.
So is there any possible clean workarounds? Sort of like lazy initialization, by some delegates or something.
Well, partially answering your question:
var Dispatchers.Konvironment: MainCoroutineDispatcher
get() = dispatcher
private set(value) {
dispatcher = value
}
private lateinit var dispatcher: MainCoroutineDispatcher
fun main() {
...
Dispatchers.Konvironment = ArbitraryMainDispatcher(Thread.currentThread()) { queue.add(it) }
...
}
will give you the desired way of assigning the value. There is no way to get rid of this additional lazyinit variable, though.
Extensions are nothing more than just some Kotlin syntax sugar for static methods which take an instance of the extended class as one of the arguments, and perform some action. If you're familiar with Java then, for example, these extensions:
// Extensions.kt
fun Foo.extendedAction() {
println(this)
}
var Foo.extendedBar: Bar
get() = this.bar
set(value) {
this.bar = value
}
are under the hood these methods in Java:
public class ExtensionsKt {
public static final void extendedAction(Foo foo) {
System.out.println(foo);
}
public static final Bar getExtendedBar(Foo foo) {
return foo.getBar();
}
public static final Bar setExtendedBar(Foo foo, Bar bar) {
foo.setBar(bar);
}
}
The conclusion which maybe drawn from the above is that extensions don't actually add anything to the extended classes' signatures, they simply decorate them with additional functionality. Or, as put in the docs:
Extensions do not actually modify classes they extend. By defining an extension, you do not insert new members into a class, but merely make new functions callable with the dot-notation on variables of this type.
So you can see, unless dispatcher somehow already exists within Dispatchers, you can't do what you want without providing an external, "backing" variable which value can be actually referenced by the extension.

Returning reference to a singleton class instance within its functions

In the following code I would like to set a reference to the class instance so that static functions can return a reference to it:
open class TestRunner {
init {
instance = this
}
companion object {
private lateinit var instance: TestRunner
fun addTestSetups(vararg testSetups: () -> TestSetup): TestRunner {
for (setup in testSetups) {
testsSetups.add(setup)
}
return instance
}
}
}
But setting instance = this is not allowed. How can I return an instance of the class from a function while keeping the class as a singleton?
If I get you right, you want something like this:
abstract class TestRunner {
companion object : TestRunner()
}
This seems to work. Instead of keeping a variable that holds a reference to the class, simply referencing the name of the class is sufficient. However, to return an instance of the class from functions, the return type must be Companion:
open class TestRunner {
companion object {
fun addTestSetups(vararg testSetups: () -> TestSetup): Companion {
for (setup in testSetups) {
testsSetups.add(setup)
}
return TestRunner
}
}
}
This is not a true singleton because you can still create a new instance if you did this:
val testRunner = TestRunner()
However, if you never create an instance but only refer to the functions statically, it does behave like a singleton and the state of any private variables inside the companion object will still be maintained.
Update:
I came across this code on the Android developer site that shows an example of a class that is setup as a singleton:
class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
private val stockManager: StockManager = StockManager(symbol)
private val listener = { price: BigDecimal ->
value = price
}
override fun onActive() {
stockManager.requestPriceUpdates(listener)
}
override fun onInactive() {
stockManager.removeUpdates(listener)
}
companion object {
private lateinit var sInstance: StockLiveData
#MainThread
fun get(symbol: String): StockLiveData {
sInstance = if (::sInstance.isInitialized) sInstance else StockLiveData(symbol)
return sInstance
}
}
}
But it should be pointed out that this example requires functions that need to return an instance to first check if the instance variable is set and if not, create a new instance. I'm not sure what the point of that is since to call the function you already have an instance. So why bother create a new instance? Doesn't seem to make any sense.
object in Kotlin is the singleton, not the class its defined within. A companion object has the extra convenience of allowing you to call it by the name of that outer class. But it otherwise shares no hierarchy with it.
To make your class subclassable, you can't define the functions in the companion object. But you can make the class abstract so it can't be instantiated unless subclassed. Then make your companion object extend the abstract class so it will have all those functions available.
abstract class TestRunner{
open fun addTestSetups(vararg testSetups: () -> TestSetup): TestRunner{
//...
return this
}
companion object: TestRunner()
}
Usage:
TestRunner.addTestSetups(someTestSetup)
Note that your singleton is not an instance of TestRunner. It is a singleton instance of a subclass of TestRunner. But since you define no extra functions and override nothing, it behaves exactly like a TestRunner.
If you want a subclass:
abstract class ExtendedTestRunner: TestRunner() {
fun someOtherFunction() {}
companion object: ExtendedTestRunner()
}
The companions are not being subclassed, but their abstract parents can be.

Access methods outside companion object - Kotlin

I'm pretty new to kotlin and I was wondering if it's possible, and if it's against best practice to access methods and variables that are outside a companion object, from within the companion object.
For example
class A {
fun doStuff(): Boolean = return true
companion object{
public fun stuffDone(): Boolean = return doStuff()
}
}
or something like that
Thank you
doStuff() is an instance method of a class; calling it requires a class instance. Members of a companion object, just like static methods in Java, do not have a class instance in scope. Therefore, to call an instance method from a companion object method, you need to provide an instance explicitly:
class A {
fun doStuff() = true
companion object {
fun stuffDone(a: A) = a.doStuff()
}
}
You can also call functions that are outside of companion object block.
class A {
fun doStuff() = true
companion object {
val a = A()
fun stuffDone() = a.doStuff()
}
}
A correct way to do what you want is:
create a instance of your main class inside Companion Objects
initialize the instance when you instance the Main Class
call the instance of the class when you need to call methods, set or
get variables.
For a better control and better decouple level, you should access/set/get
stuff from the main class (A) from the Companion Object instead of calling getInstance() to access the Main Class stuff.
Example:
class A {
private val myPrivateVariable:String = "MY_STUFF"
init{
setupInstance(this#A)
}
companion object{
private val instance:A? = null
fun setupInstance(a:A){
this.instance = a
}
//IF YOU WANT TO ACCESS CLASS A METHODS/VARIABLES DIRECTLY YOU CAN CALL IT
fun getInstance():A{
return this.instance?.let{
it
}?:throw NullPointerException("INSTANCE NOT SET YET")
}
//ACCESSING CLASS A VARIABLES FROM COMPANION OBJECT (BETTER ERROR CONTROL AND DECOUPLED)
fun setMyVariable(string:String){
this.getInstance().myPrivateVariable = string
}
fun getMyVariable(string:String) = this.getInstance().myPrivateVariable
}
}