Home > Blockchain >  What does ::SomeClass reference in Kotlin
What does ::SomeClass reference in Kotlin

Time:12-05

Take the following code sample:

class Food(var size: Int, val doSomething: () -> Unit) {
    init {
        var t = 0
    }

    operator fun invoke() {
        doSomething()
    }
}

var x = ::Food
x.invoke(10) {
    var x = 1
}

When x.invoke(10) is called, the init in Food is called. But the invoke function is not called. This seems odd. What is ::Food referencing and what exactly is x.invoke calling if the actual invoke function is not even being called?

It appears that x refers to the constructor. You can call the constructor by just calling:

x(10) {}

But including the .invoke does nothing. The constructor still gets called (and hence the init) but the invoke function itself does nothing. Not even sure why this is even allowed.

I have a feeling that .invoke is calling Kotlin's own built-in invoke function and NOT the operator function that is in the class.

CodePudding user response:

the invoke function can be called by writing () behind an instance of the class. so simply writing

x.invoke(10) {
    println("test")
}()

could work for your example and prints "test". Or this for example

val s = x.invoke(10) {
    println("test")
}

s()
s()

prints test twice

CodePudding user response:

It appears that x refers to the constructor.

Your observation is correct. x(10) {} and x.invoke(10) {} are indeed the same. The former is just a syntactic sugar for the latter, in the same way that 1 1 is just a syntactic sugar for 1.plus(1).

In fact, this is the whole point of the invoke operator, and the reason why you can directly call function/constructor references. If x has declared an invoke(...) operator, then x(...) means x.invoke(...).

::Food, being a reference to the constructor of Food, is of type KFunction2<Int, () -> Unit, Food>. This type is specified to have a invoke() operator that takes an Int and () -> Unit, and returns a Food. When you do x(10) {} or x.invoke(10) {}, you are calling that invoke operator, not the one in Food.

To call the invoke in Food, you need an instance of Food, which is exactly what x(10) {} or x.invoke(10) {} returns.

x(10) {
    println("foo")
}.invoke()

// or

x(10) {
    println("foo")
}()

Either of the above would print "foo".

  • Related