Search code examples
kotlinnamed-parameters

How can I force calls to some constructors/functions to use named arguments?


I have some constructors and functions that I'd like to always be called with named arguments. Is there a way to require this?

I'd like to be able to do this for constructors and functions with many parameters and for those that read more clearly when named arguments are used, etc.


Solution

  • In Kotlin 1.0 you can do this by using Nothing from the stdlib.

    In Kotlin 1.1+ you will get "Forbidden vararg parameter type: Nothing" but you can replicate this pattern by defining your own empty class with a private constructor (like Nothing), and using that as the first varargs parameter.

    /* requires passing all arguments by name */
    fun f0(vararg nothings: Nothing, arg0: Int, arg1: Int, arg2: Int) {}
    f0(arg0 = 0, arg1 = 1, arg2 = 2)    // compiles with named arguments
    //f0(0, 1, 2)                       // doesn't compile without each required named argument
    
    /* requires passing some arguments by name */
    fun f1(arg0: Int, vararg nothings: Nothing, arg1: Int, arg2: Int) {}
    f1(arg0 = 0, arg1 = 1, arg2 = 2)    // compiles with named arguments
    f1(0, arg1 = 1, arg2 = 2)           // compiles without optional named argument
    //f1(0, 1, arg2 = 2)                // doesn't compile without each required named argument
    

    It also works in Kotlin 1.7 with Nothing, but it's necessary to suppress the compilation error:

    ...
    @Suppress("FORBIDDEN_VARARG_PARAMETER_TYPE", "UNUSED_PARAMETER")
    vararg nothings: Nothing,
    ...
    

    As Array<Nothing> is illegal in Kotlin, a value for vararg nothings: Nothing can't be created to be passed in (short of reflection I suppose). This seems a bit of a hack though and I suspect there is some overhead in the bytecode for the empty array of type Nothing but it appears to work.

    This approach does not work for data class primary constructors which cannot use vararg but these can be marked as private and secondary constructors can be used with vararg nothings: Nothing.