I want to choose function reference before applying it to arguments, but Kotlin cannot infer its type.
Suppose I have a class
class Circle(val radius: Float)
and a function
fun sortByRadius(circles: MutableList<Circle>, ascending: Boolean) {
if (ascending)
circles.sortBy { it.radius }
else
circles.sortByDescending { it.radius }
}
I want too rewrite this function body to something like this:
circles.(
if (ascending) MutableList<Circle>::sortBy
else MutableList<Circle>::sortByDescending
) { it.radius }
but it does not work. Also I found out that
(MutableList<Circle>::sortBy)(circles) { it.radius }
almost works, Kotlin just can not infer Float
type of radius; so I wonder how to specify it. Then we could write
(if (ascending) MutableList<Circle>::sortBy
else MutableList<Circle>::sortByDescending)(circles) { it.radius }
Nice question, and it doesn't seem to be possible (using function references). I've tried to specify expected type explicitly:
val f: MutableList<Circle>.((Circle) -> Float) -> Unit =
if (ascending) MutableList<Circle>::sortBy else MutableList<Circle>::sortByDescending
but the error message says
Type inference failed. Please try to specify type arguments explicitly.
and the grammar doesn't allow it:
callableReference
: (receiverType? '::' (simpleIdentifier | 'class'))
;
i.e. ::
can only be followed by an identifier or class
. Which is a strange hole because Java grammar does allow type parameters before method name.
Bound references don't help either:
(circles::sortBy) { it.radius } // doesn't compile
Not even explicit type works, which quite surprised me:
val f: ((Circle) -> Float) -> Unit = circles::sortBy
but this does:
val f: ((Circle) -> Float) -> Unit = { circles.sortBy(it) }
So ultimately you can write (parentheses around lambdas required)
val f: ((Circle) -> Float) -> Unit =
if (ascending) ({ circles.sortBy(it) }) else ({ circles.sortByDescending(it) })
f { it.radius }
but probably not want to!