Kotlin: Can I assign a function to a variable in a companion object from main? - kotlin

New to kotlin, wondering if it's possible to dynamically assign
a function to a companion object's variable. Read the docs and some answers here but there's no mentioning about this.
class Printer {
companion object {
fun printAnything() {
println("printing anything..")
}
}
}
fun printA() {
println("printing A!")
}
fun main(args: Array<String>) {
printA()
Printer.printAnything = :: printA // doesn't compile, perhaps a different way?
}

You can't reassign a function that was declared with fun. It will always point to the same function. But you can make a var that holds a reference to a function. A var or val property holding a function can be invoked as a function, the same as if it was a fun declaration.
fun defaultPrintAnything() {
println("printing anything...")
}
var printAnything = ::defaultPrintAnything
fun printA() {
println("printing A!")
}
fun main() {
printAnything() // calls defaultPrintAnything
printAnything = ::printA
printAnything() // calls printA
}
You can make a variable like this anywhere you like, whether it's in a companion object or not. So yes, you can make your Printer companion object this way:
class Printer {
companion object {
var printAnything = {
println("printing anything..")
}
}
}

Related

Inherit Companion Obejct in Children - Kotlin

I've read that static methods cannot overridden in Kotlin, so I'm not sure if this is possible, but not being able to do so would result in a lot of repetitious code. Is there any way to achieve the same behavior while moving the companion object into the Parent? Here is what I have so far
Parent.kt
abstract class Parent {
protected val TAG = this::class.java.simpleName
}
Brother.kt
class Brother: Parent() {
companion object {
#Volatile private var instance: Brother? = null
fun getInstance() = instance ?: synchronized(this) {
instance ?: Brother().also { instance = it }
}
}
}
Sister.kt
class Sister: Parent() {
companion object {
#Volatile private var instance: Sister? = null
fun getInstance() = instance ?: synchronized(this) {
instance ?: Sister().also { instance = it }
}
}
}
main()
fun main() {
println("Hello, ${Brother.getInstance().TAG}")
println("Hello, ${Sister.getInstance().TAG}")
}
Console Output:
Hello, Brother Hello, Sister
Maybe this will work for what you're trying to do.
You can create a superclass for objects that do this pattern:
open class SingletonAccessor<T: Any> (private val constructor: () -> T){
#Volatile private var instance: T? = null
fun getInstance() = instance ?: synchronized(this) {
instance ?: constructor().also { instance = it }
}
}
And then inherit it from your implementation class companion objects:
class Brother private constructor(): Parent() {
companion object: SingletonAccessor<Brother>(::Brother)
}
class Sister private constructor(): Parent() {
companion object: SingletonAccessor<Sister>(::Sister)
}
This pattern isn't much different from simply making Brother and Sister objects, since they have no constructor parameters, but maybe this is just a simplified example.
Based on #Tenfour04's answer, I've come up with an alternate approach, which incorporates the SingletonAccessor into the Parent
abstract class Parent<T>(private val constructor: () -> T) {
#Volatile private var instance: T? = null
protected val TAG = this::class.java.simpleName
fun getInstance() = instance ?: synchronized(this) {
instance ?: constructor().also { instance = it }
}
}
The implementation in the children is the same as before.
Let me know if this answer can be improved further. In particular, I would like to do in the class declaration class Parent<T: Parent>, but that doesn't compile. Is there a way to limit the type parameter to itself and its children?

What are the differences between a companion object function and package level functions?

Whats the difference between having a function on a companion object and having the function at package level?
class Foo {
companion object {
fun bar() = println("bar")
}
}
fun bar() = println("bar")
You can call both pretty similar
class B {
fun print() {
Foo.bar()
}
fun print2() {
bar()
}
}

Is it possible to verify at compile time whether the required function is called for the Factory Class in Kotlin?

class ModelFactory {
fun setA() : ModelFactory {
// blabla...
}
fun setB() : ModelFactory {
// blabla...
}
fun setC() : ModelFactory {
// blabla...
}
fun build() : Model {
// An error occurs if any of setA, setB, and setC is not called.
}
}
//example
fun successTest() {
ModelFactory().setA().setB().setC().build() // No error occurs at compile time
}
fun failTest() {
ModelFactory().setA().build() // An error occurs at compile time because setB and setC are not called.
}
It's awkward grammatically, but I think it's been expressed what I want.
I have already implemented an error-raising runtime for this requirement, but I want to check this at compile time.
If possible, I think I should use annotations. But is this really possible at compile time?
With Kotlin, I have been avoiding builder pattern, as we can always specify default values for non-mandatory fields.
If you still want to use a builder pattern, you can use Step builder pattern that expects all mandatory fields to be set before creating the object. Note that each setter method returns the reference of next setter interface. You can have multiple Step builders based on the combination of mandatory fields.
class Model(val a: String = "", val b: String = "", val c: String = "")
class StepBuilder {
companion object {
fun builder(): AStep = Steps()
}
interface AStep {
fun setA(a: String): BStep
}
interface BStep {
fun setB(b: String): CStep
}
interface CStep {
fun setC(c: String): BuildStep
}
interface BuildStep {
//fun setOptionalField(x: String): BuildStep
fun build(): Model
}
class Steps : AStep, BStep, CStep, BuildStep {
private lateinit var a: String
private lateinit var b: String
private lateinit var c: String
override fun setA(a: String): BStep {
this.a = a
return this
}
override fun setB(b: String): CStep {
this.b = b
return this
}
override fun setC(c: String): BuildStep {
this.c = c
return this
}
override fun build() = Model(a, b , c)
}
}
fun main() {
// cannot build until you call all three setters
val model = StepBuilder.builder().setA("A").setB("B").setC("C").build()
}

How to perform companion object lateinit is initiallize check

If I have a lateinit variable, I could check is it initialized using (this::lateInitVar.isInitialized), as shown in https://stackoverflow.com/a/47860466/3286489
However if the variable is a companion object, how could I do so?
e.g.
class MyClass {
companion object {
lateinit var myGlobalLateInit: String
}
lateinit var myLocalLateInit: String
fun settingVariable() {
if (!this::myLocalLateInit.isInitialized) {
myLocalLateInit = "I am set"
}
if (!MyClass::myGloablLateInit.isInitialized) { // This line will error out. How could I set it?
myGloablLateInit = "I am set"
}
}
}
You could extract it into a function inside the companion object:
class MyClass {
companion object {
lateinit var myGlobalLateInit: String
fun isMyGlobalLateInitInitialized() = ::myGlobalLateInit.isInitialized
}
fun settingVariable() {
if (!isMyGlobalLateInitInitialized()) {
myGlobalLateInit = "I am set"
}
}
}

Using lambdas does not compile when trying to pass in a method expecting a SAM interface

I am trying to understand lambdas and Kotlin. I created this trivial example
interface OnClickListener {
fun onClick(s: String)
}
class Button {
var clickListener: OnClickListener? = null
fun setOnClickListener(listener: OnClickListener?) {
clickListener = listener
}
fun click() {
clickListener?.onClick("hello")
}
}
fun main(args: Array<String>) {
val b = Button()
b.setOnClickListener(
object : OnClickListener {
override fun onClick(s: String) {
println(s)
}
}
)
/*
Variation 1
val l = {
s -> println(s)
}
b.clickListener = l*/
/*
Variation 2
b.setOnClickListener{
s -> println(s)
}
*/
/*
Variation 3
b.clickListener = {
s -> println(s)
}
*/
b.click()
}
So the above code only compiles if I pass an anonymous object. But I wanted to figure out how to use the lambdas.
None of the 3 variation to use a lambda compiles.
I thought since the OnClickListener is a SAM I should easily be able to pass in a lambda
What am I doing wrong here?
To be able to use a lambda, you need to use a Java interface.
First, create a Java file and create an interface:
public interface OnClickListener {
void onClick(String s);
}
Then in your main:
b.setOnClickListener(OnClickListener { s ->
println(s)
})
As for your Button class:
class Button {
var clickListener: OnClickListener? = null //You can use this too but there's another way as well.
//lateinit var clickListener: OnClickListener //Telling the compiler that you will initialize it later on.
fun setOnClickListener(listener: OnClickListener) { //removed redundant ? from the function signature.
clickListener = listener
}
fun click() {
clickListener?.onClick("hello") //Incase of lateinit, you don't need a '?' anymore
}
}
SAM conversion only works between a Java code and a Kotlin code.
EDIT: Since in Kotlin, you can store a function in a variable as well, here is my another two cents on how you can do it in a different way:
class Button {
lateinit var myFunction: (String) -> Unit
fun setOnClickListener(block : (String) -> Unit) {
myFunction = block //storing state of your 'listener'
}
fun onClick() = myFunction.invoke("Invoked from onClick function")
}
Then in your main:
fun main() {
val button = Button()
button.setOnClickListener { s ->
println(s)
}
button.onClick()
}
As Taseer Ahmad points out, SAM conversion only works for Java interfaces since Kotlin already has proper function types. Of course, an easy way around this is to simply define a second setOnClickListener method that takes a function type
class Button {
var clickListener: OnClickListener? = null
fun setOnClickListener(listener: OnClickListener?) {
clickListener = listener
}
inline fun setOnClickListener(crossinline listener: (String) -> Unit) {
setOnClickListener(object : OnClickListener {
override fun onClick(s: String) = listener(s)
})
}
fun click() {
clickListener?.onClick("hello")
}
}
This then allows you to write b.setOnClickListener { println(it) }. I always inline methods like this as a habit, but it's not really required, so you can remove the inline and crossinline if you want.