Returning reference to a singleton class instance within its functions - kotlin

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.

Related

How to get both static and instance access to a classes field

Suppose I have an abstract superclass A. That class has a property abstract val predicate: (ModelClass) -> Boolean.
Let B be a subclass.
I want to be able to do both of the following:
Use the predicate from an instance aInstance.predicate
Also use that predicate elsewhere, without having to create an instance to get that predicate B.predicate
How can I do this.
I don't think this is possible.
There is no such thing as an abstract static method in Kotlin or Java.
Perhaps this will give more insight.
Does your class need to be abstract? Maybe the code below can be useful:
open class MyClass {
companion object myCompanion {
val myStatic = "MyClass"
}
open val myStatic = myCompanion.myStatic
}
class MySubClass : MyClass() {
companion object myCompanionSubClass {
val myStatic = "MySubClass"
}
override var myStatic = myCompanionSubClass.myStatic
}
fun main() {
println(MyClass.myStatic)
val t = MyClass()
println(t.myStatic)
println(MySubClass.myStatic)
val subClass = MySubClass()
println(subClass.myStatic)
}
In this code you can define a static property and use it from the class or any instance. It is also possible to override the property in a subclass and use it in the same way.

Confused about Kotlin's companion object definition

When i reach the companion object section in the ebook "Kotlin in action" it said that:
"if you need to write a function that can be called
without having a class instance but needs access to the internals of a class, you can write it as a member of an object declaration inside that class"
As my understanding this means a function of the companion object can access the method and properties of the class that contain it. But when i try to implement this i can't access the members of the class from its companion object'function:
class Normal() {
var name: String = "hallo"
companion object {
fun printName() {
println(name) // ERROR!!! unresolved reference name
}
}}
Did i misunderstood about this concept?
Method inside companion are kind of static by default(compared to Java & also this is how you achieve static kind of things in Kotlin) and you can not access normal variable from static method.
Same is happening here.
Edit:-
The definition in book is confusing, A companion object is not part of an instance of a class. You can't access members from a companion object, just like in Java you can't access members from a static method. But in case of utility classes where you just need to perform some operation you can call Static method which create a new instance of class and the perform some functions.
For example you can check answer by #user8320224, I am also quoting his code here,
class Normal {
private var name: String = "hallo"
private fun printName() {
println(name)
}
companion object {
fun factoryNormal(): Normal {
val normal = Normal()
normal.printName()
normal.name = "new name"
normal.printName()
return normal
}
}
}
Static members have access to the internals of a class, for example private members
class Normal() {
private var name: String = "hallo"
private fun printName() {
println(name)
}
companion object {
fun factoryNormal(): Normal {
val normal = Normal()
normal.printName()
normal.name = "new name"
normal.printName()
return normal
}
}}
companion object is the same as public static final class in Java. Therefore you can't access to var name.
Maybe this will help you:
class Normal() {
companion object {
#JvmStatic
var name: String = "hallo"
// This annotation will be helpful if you are calling
// this from Java, so it goes like Normal.printName();
#JvmStatic
fun printName() {
println(name)
}
}
}
Now you can use this in Kotlin:
Normal.name = "new name"
Normal.printName()
and if you want to use this in Java, then:
Normal.setName("new name");
Normal.printName();
A companion object is the same as "static" in Java. It doesn't actually have any instance of your class in it. So if your printname() method just said println("Hello again!") you could do the following:
println(Normal().name) // creates a new instance of Normal class and prints "hallo"
Normal.printname() // Does not create a new instance of Normal class but instead just prints "Hello again!" since we can access static methods without requiring an instance of a class itself.
Note that we didn't actually create a new Normal in that second line (no constructor brackets). The printname() method can be thought of as belonging to the definition of a class, rather than an example or instance of that class.
It's rather like the manual for a car; it can reference and talk about the internals of a car, but you need to have an actual car to do anything fun with the manual.
We can access the internals of an instance of the class, if we have one. So passing in an instance of the class would work:
class Normal() {
private var name: String = "hallo"
companion object {
fun printName(normal : Normal) {
println(normal.name) // Note that I made the "name" var private
}
}}
The companion object can also access anything that's within the companion object itself, so this would also work:
class Normal() {
companion object {
private var name: String = "hallo"
fun printName() {
println(name) // Note I moved the "name" var into the companion object
}
}}
And you can combine these:
class Normal() {
private var name: String = "Vilpe89"
companion object {
private var greeting: String = "Hello "
fun printName(normal : Normal) {
println("$greeting ${normal.name}!")
}
}}
Now you could call the above code like this:
Normal.printname(Normal()) // uses Normal's companion object
// method on an instance of Normal,
// and prints "Hello Vilpe89!"
This is very different to what would happen if they were separate classes:
class Normal() {
private var name: String = "Vilpe89"
}
class Greeting() {
private var greeting: String = "Hello "
fun printName(normal : Normal) {
println("$greeting ${normal.name}!") // This won't compile, because
// Greeting can't see normal.name
// if it's private.
}
}

function extension for class in another class

I want to make a function extension for class inside of another class (for String in ModelAndView, not for inner), but have not found a way to do this without class inheritance. Is it possible at all?
Example of class extension:
class MyModelAndView : ModelAndView() {
infix fun String.to(value: Any?) {
addObject(this, value)
}
}
You can create member extension functions in classes, but these extensions can only be accessed in the class':
class X {
fun String.ext() = println("extension on $this called")
fun useExtension() {
val text: String = "myText"
text.ext()
}
}
You can only use this extension inside the class, as shown in useExtension, and also in the context of that class, which for instance can be used in with:
with(x) { "abc".ext() }
It's not recommended to do this, although it makes sense when writing DSLs for example.

Kotlin static methods and variables

I want to be able to save a class instance to a public static variable but I can't figure out how to do this in Kotlin.
class Foo {
public static Foo instance;
public Foo() {
instance = this;
}
}
Update: since this answer is getting a decent amount of upvotes, I really wanted to say that you shouldn't do the below, but instead just use object Foo { ... }, like Roman rightly points out in the comment.
Previous answer:
The closest thing to Java's static fields is a companion object. You can find the documentation reference for them here: https://kotlinlang.org/docs/reference/object-declarations.html#companion-objects
Your code in Kotlin would look something like this:
class Foo {
companion object {
lateinit var instance: Foo
}
init {
instance = this
}
}
If you want your fields/methods to be exposed as static to Java callers, you can apply the #JvmStatic annotation:
class Foo {
companion object {
#JvmStatic lateinit var instance: Foo
}
init {
instance = this
}
}
It looks that you want to define a singleton object. It is supported in Kotlin as a first-class concept:
object Foo {
...
}
All the boilerplate code with static field and constructor is taken care by the Kotlin automatically. You don't have to write any of that.
From the Kotlin code you can refer to the instance of this object simply as Foo. From the Java code you can referer to the instance of this object as Foo.INSTANCE, because the Kotlin compiler automatically creates the corresponding static field named INSTANCE.
first you create a simple class then after create a block followed by companion object keyword
for example:
class Test{
companion object{
fun getValue(): String{
return "Test String"
}
}
}
you can call this class function using class name dot function name
for example:
// here you will get the function value
Test.getValue()
You can create a companion object for the class, and if you want the field to be static you can use the annotation #JvmStatic. Companion object have access to private members of the class it is companion for.
See below an example:
class User {
private lateinit var name: String
override fun toString() = name
companion object {
#JvmStatic
val instance by lazy {
User().apply { name = "jtonic" }
}
}
}
class CompanionTest {
#Test
fun `test companion object`() {
User.instance.toString() shouldBe "jtonic"
}
}

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
}
}