1

It seems that Kotlin does not support getting local functions etc. Please see the example below:

fun <T> MutableList<T>.filterOnCondition(condition: (T) -> Boolean): MutableList<T>
{ 
    // For the printline, trying to get the function name, 
    // which in this case is passedAsCondition
    println(condition.reflect()!!.instanceParameter!!.name)
}

fun passedAsCondition (number: Int, multipleOf : Int): Boolean
{
    return number % multipleOf == 0
}

numbers.filterOnCondition { passedAsCondition(it, 5) }

Kotlin returns this error as it has not been mapped out yet:

"kotlin.reflect.jvm.internal.KotlinReflectionInternalError: Introspecting local functions, lambdas, anonymous functions and local variables is not yet fully supported in Kotlin reflection"

(https://github.com/JetBrains/kotlin/blob/master/core/reflection.jvm/src/kotlin/reflect/jvm/internal/EmptyContainerForLocal.kt#L41)

BUT, surely this is possible to do via Java, is it not?

s1m0nw1
  • 76,759
  • 17
  • 167
  • 196
astone26
  • 1,222
  • 11
  • 16
  • I can write `Arrays.asList(5, 6, 10, 13, 15, 24).stream().filter(x -> x % 5 == 0).forEachOrdered(System.out::println);` - not sure what you're asking... something about passing a function to filter? – Elliott Frisch Feb 16 '18 at 07:15
  • I am trying to get the name of the function that is passed into filterOnCondition. For the println(), I would like to see passedAsCondition returned. – astone26 Feb 16 '18 at 07:19
  • @Lander, You're reflecting on the lambda. `passedAsCondition` is in the lambda body. – chris Feb 16 '18 at 07:26

1 Answers1

1

It's an anonymous function, thus it's name will be <anonymous>:

val x: (Int) -> Boolean = { passedAsCondition(it, 5) }
println(x.reflect()?.name) //prints <anonymous>

When you have a lambda { passedAsCondition(it, 5) } how would you expect the reflection to work here? passedAsCondition is a simple call made inside the lambda, but you're invoking the reflect on an unnamed, anonymous, lambda, which does not have a name.

Ordinary functions can be used with method references which of course do have a name:

fun x(a: Int): Boolean {
    passedAsCondition(a, 5)
    return true
}
println(::x.name) //gives x

As a result, making use of proper reflection, the following works:

fun main(args: Array<String>) {
    mutableListOf(1).filterOnCondition(::passedAsCondition)
}


fun <T> MutableList<T>.filterOnCondition(
    condition: KFunction2<@ParameterName(name = "number") Int, @ParameterName(name = "multipleOf") Int, Boolean>
) {
    println(condition.name)
}

fun passedAsCondition(number: Int, multipleOf: Int): Boolean = number % multipleOf == 0
s1m0nw1
  • 76,759
  • 17
  • 167
  • 196
  • Thank you, s1m0nw1. I'm quite new to Kotlin here. Is it possible to get the function name of passedAsCondition from within the lambda? – astone26 Feb 16 '18 at 07:34
  • 1
    FWIW, if the question sounds unorthodox, you can actually do this in C#, where it used to be semi-common for passing a property name without using a hardcoded string. – chris Feb 16 '18 at 08:01
  • An example of what @chris is referring to: [this](https://stackoverflow.com/questions/1718037/reflecting-parameter-name-abuse-of-c-sharp-lambda-expressions-or-syntax-brillia) – Salem Feb 16 '18 at 08:18
  • @s1m0nw1: I see, but would you not lose the ability to pass params into passedAsCondition? – astone26 Feb 16 '18 at 08:26
  • 1
    You can still invoke the function, but the arguments need to be passed as extra parameters but it quickly gets ugly tbh. What’s your use case anyways – s1m0nw1 Feb 16 '18 at 08:29