3
votes

In Kotlin we can't create class which implements 2 lambdas with different signature, like this:

class Test<T> : (T) -> Unit, () -> T {
    ...
}

which gives following error:

Type parameter R of 'Function' has inconsistent values: Unit, T

I understand the reason why it happens: all lambdas are FunctionN interfaces and all FunctionN interfaces extend some marker interface called Function which can't be invoked. But also last one is the root cause of generics conflict and error mentioned above.

My question probably to Kotlin team: is there any reason why all FunctionN extend Function interface? Maybe some internal/bytecode stuff which isn't obvious for us, but makes some tricky optimization for performance underneath.

2
maybe you want to ask this question on discuss.kotlinlang.org and cross-link both?Roland

2 Answers

2
votes

https://github.com/JetBrains/kotlin/blob/master/spec-docs/function-types.md gives some limited information about the use of Function:

  • Introduce a physical class Function and unlimited number of fictitious (synthetic) classes Function0, Function1, ... in the compiler front-end

  • Provide a way to get arity of an arbitrary Function object (pretty straightforward).

  • Hack is/as Function5 on any numbered function in codegen (and probably KClass.cast() in reflection) to check against Function and its arity.

(note: the fictitious Function* classes are in kotlin package, kotlin.jvm.functions.Function* interfaces are real.)

The problems this approach fixes are listed in the Goals section:

  • Get rid of 23 hardwired physical function classes. One of the problems with them is that they should be effectively duplicated in reflection which means a lot of physical classes in kotlin-runtime.jar.
  • Make extension functions assignable to normal functions (and vice versa), so that it's possible to do listOfStrings.map(String::length)
  • Allow functions with more than 23 parameters, theoretically any number of parameters (in practice 255 on JVM).
  • At the same time, allow implementing Kotlin functions easily from Java: new Function2() { ... } and overriding invoke only would be the best. Enabling SAM conversions on Java 8 would also be terrific.
0
votes

I think you can simply overload invoke method manually to get the behavior of lamdbas:

class Test<T> {
    operator fun invoke(p1: T) {
    }

    operator fun invoke(): T {
        return ...
    }
}

To contact the Kotlin's team you can find them on the forum (https://discuss.kotlinlang.org), or file an issue (https://youtrack.jetbrains.com/issues/KT).