In the following code,
class IncWrapper<T> (val wrapped: T, val base: Int) {
fun incFunction(increment: Int, func: T.(Int) -> Int): Int {
return increment + wrapped.func(base)
}
}
class ClassWithIndecentlyLongName {
fun square(x: Int) = x * x
}
fun main() {
val wrapper = IncWrapper(ClassWithIndecentlyLongName(), 2)
val computed = wrapper.incFunction(1, ClassWithIndecentlyLongName::square)
println(computed)
}
we pass a reference to a method of the wrapped class ClassWithIndecentlyLongName
. Since it is known at the call site that this class is expected as the receiver of the method, it seems awkward / redundant to pass the name of the class again. I'd expect something like ::square
to work, but it doesn't. If such feature is missing, what might be the reasons?
(The question arose from an attempt to refactor some very wordy Java code converting lots of fields of one class to another.)
The variable name is known as the receiver of the call because it's the variable that the extension function is acting upon. In this case, the block passed to let() is only evaluated if the variable name was non-null. This means that inside the block, the value n is guaranteed to be non-null. More on this here.
With Context Receivers we can add one or more contexts to our functions or methods. This provides the functionality of the declared context within our function, like having another this in that function. We are then able to call methods of that context as if our function is part of the object.
It means that functions can be assigned to the variables, passed as an argument, or returned from another function. While Kotlin is statically typed, to make it possible, functions need to have a type.
Kotlin with. Like apply , with is used to change instance properties without the need to call dot operator over the reference every time. data class Person(var name: String, var tutorial : String) var person = Person("Anupam", "Kotlin") with(person) { name = "No Name" tutorial = "Kotlin tutorials" }
Using just ::square
would mean, it is part of your package or the file/class where it is called from. But that's not correct in that case.
If you have such long names you could switch from the function reference to the actual lambda instead, e.g.:
wrapper.incFunction(1) { square(it) }
If you have more parameter, then a typealias is probably more helpful instead, e.g.
typealias Functions = ClassWithIndecentlyLongName // choose a name that's more appropriate
// and calling it as follows:
wrapper.incFunction(1, Functions::square)
Alternatively import that class with an alias, e.g.:
import ClassWithIndecentlyLongName as ShortName
However, the better approach is probably to just discard the indecently long name and replace it with something more appropriate instead.
Finally, if you really want to just use ::square
you can still do so, if you supply as many wrapper functions that you need, e.g.:
fun square(c : ClassWithIndecentlyLongName, i : Int) = c.square(i)
// calling it, now works as you wanted:
wrapper.incFunction(1, ::square)
Now: why it is that way? I can only guess. But it makes sense to me, that you need to specify exactly where that function can be found. I think it would rather complicate the code if you can never be sure which function is exactly behind the one specified.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With