Kotlin - Companion Object with Receiver Function

Viewed 39

I guess it's an outright "NO", but here is my class

class KotlinReceiverFunction {

    val multiplyBy = fun Int.(value: Int) = this*value

    companion object {
        fun printMultiplicationResult(a: Int, b: Int) = a.multiplyBy(b) // error
    }
}

My question - is Receiver Function only allowed within a specific scope i.e. same as Lambdas? Or, can I get to work somehow in a companion object?

Regards

2 Answers

There are no restrictions on where a function with a receiver could be used. The problem in your case is different: multiplyBy is an instance member, so you need an instance of KotlinReceiverFunction to use it. It would be exactly the same if this function would not use a receiver:

val multiplyBy = fun (value1: Int, value2: Int) = value1*value2

companion object {
    fun printMultiplicationResult(a: Int, b: Int) = multiplyBy(a, b) // error
}

To fix the problem you need to initialize an instance of KotlinReceiverFunction:

fun printMultiplicationResult(a: Int, b: Int) =
    with(KotlinReceiverFunction()) { a.multiplyBy(b) } // works

Although, I think this is not exactly what you need.

This has nothing to do with receivers. You are using the correct receiver. It's just that things declared outside the companion object is out of scope inside the companion object:

class KotlinReceiverFunction {
    val foo = 1
    companion object {
        fun bar() {
            println(foo) // error
        }
    }
}

Think of KotlinReceiverFunction and its companion object as two disconnected things. Under the hood on the JVM, they are just two separate classes KotlinReceiverFunction and KotlinReceiverFunction$Companion, each with their own instance members.

In the companion object, You would need an instance of KotlinReceiverFunction to access its foo property. This instance acts as the receiver.

companion object {
    fun bar() {
        println(KotlinReceiverFunction().foo) // OK
    }
}

Similarly, the multiplyBy function needs an instance of KotlinReceiverFunction as its receiver (dispatch receiver). But this function also needs an Int as a receiver (extension receiver)!

This makes it a little harder to access than foo when you are in the companion object. You would need to provide the instance of KotlinReceiverFunction with a scope function, as in broot's answer.


If you just declare the function inside the companion object, then it will work as you expect:

class KotlinReceiverFunction {
    companion object {

        val multiplyBy = fun Int.(value: Int) = this*value
        fun printMultiplicationResult(a: Int, b: Int) = a.multiplyBy(b)
    }
}

I don't see a reason why this needs to be a val initialised with an anonymous function. You could have just done:

private fun Int.multiplyBy(value: Int) = this * value
Related