atok
atok

Reputation: 5938

How to make the argument default?

I've found a strange case of the default argument value not being default:

class Dog
class DogHouse(dog: Dog)

inline fun <T: Any, A: Any> build(sth: String = "", call: (A) -> T) {}

fun main(args: Array<String>) {
    build(call = ::DogHouse)
    build(::DogHouse)  // This line fails to compile
}

The compilation error:

Error:(11, 5) Kotlin: Type inference failed: inline fun <T : Any, A : Any> build(sth: String = ..., call: (A) -> T): Unit
cannot be applied to
(KFunction1<@ParameterName Dog, DogHouse>)

Error:(11, 11) Kotlin: Type mismatch: inferred type is KFunction1<@ParameterName Dog, DogHouse> but String was expected

Error:(11, 21) Kotlin: No value passed for parameter call

Upvotes: 2

Views: 226

Answers (1)

hotkey
hotkey

Reputation: 147911

When you make a call to a function with default arguments, you still cannot skip them implicitly and pass the following ones, you can only use explicit named arguments to do that.

Example:

fun f(x: Int, y: Double = 0.0, z: String) { /*...*/ }
  • You can always pass x as non-named argument, because it is placed before the default argument:

    f(1, z = "abc")
    
  • You can, of course, pass all the arguments in their order:

    f(1, 1.0, "abc")
    
  • But you cannot skip a default argument and pass those following it without an explicit label:

    f(1, "abc") // ERROR
    f(1, z = "abc") // OK
    

(demo of this code)

Basically, when you don't use named arguments, the arguments are passed in the order of the parameters, without skipping the default arguments.

The only exception is made for the code block syntax of the last argument when it has functional type:

fun g(x: Int = 0, action: () -> Unit) { action() }

g(0) { println("abc") }
g { println("abc") } // OK

Upvotes: 7

Related Questions