Search code examples
genericslambdakotlininline

Lambda type with variable number of args in Kotlin?


Is it possible to receive as an inline lambda parameter a function type which has a guaranteed return type R but a variable number of arguments? For simplicity, consider the following:

inline fun <R> Boolean?.tfn(tru:()->R, fls:()->R, nul:()->R) =
  if (this == null) nul() else if (this) tru() else fls()

Let's assume I have other inline functions that also take lambda parameters that might be of type (A)->R or (A,B)->R or (A,B,C)->R, whose parameters I'd like to pass to this function. They will all provide an R but they all must be invoked to get the R, without knowing the number/type/values of the parameters in this function. Is there a way to generically modify the function above to:

  1. capture the generic case of any lambda parameter returning R for its inputs
  2. avoid any changes to the other inline functions that will be calling this function
  3. maintain the inline efficiencies

Solution

  • This is impossible

    Kotlin uses static, strong typing, and the compiler needs to know the exact type of the lambda parameters at compile time. Internally lambdas are actually implementations of one of the kotlin.jvm.functions interfaces (for JVM or Android), like this one:

    /* A function that takes 1 argument. */
    public interface Function1<in P1, out R>
    

    These interfaces define the exact number of parameters and their types. Because of that it's not possible to create a vararg lambda in Kotlin. This is of course related to the fact, that vararg in JVM is just a syntax sugar that internally uses ordinary arrays, but is not a type system construct by itself, so you can't treat varargs like types.

    Dependent types

    One suggestion to solve your problem is to use an Array or a Collection as a function parameter, or pass in arbitrary Function<R>, but this solution is limited in the way that there is no way for to statically enforce the same amount of the parameters of each passed function, because type system itself doesn't know about the size of collection/array or parameter count of Function<R>.

    To solve your problem entirely you need a language with dependent type system.