Johan
Johan

Reputation: 40500

Passing vargs values to another function with multiple parameters in Kotlin?

I have two extension functions declared in Kotin (1.3):

fun SomeClass.fooBuilder(vararg x: String, fn: ((String) -> Unit)? = null): Result.Builder = TODO()
fun SomeClass.foo(vararg x: String, fn: ((String) -> Unit)? = null): Result = fooBuilder(*x, fn).build()

What I want to do is to call fooBuilder from foo and simply call build() on the result returned from fooBuilder.

Unfortunately the code above doesn't compile since the call to fooBuilder(*x, fn).build() fails with:

Error:(28, 143) Kotlin: Type mismatch: inferred type is ((String) -> Unit)? but String was expected

I.e. the compiler seem to think that I want to pass additional string (x) arguments but what I actually want to pass is the function.

How can I resolve this and while retaining the option to use to omit the parentheses when specifying fn as in this example:

SomeClass().foo("x") { str -> println("Hello $str") }

Upvotes: 0

Views: 3938

Answers (3)

gidds
gidds

Reputation: 18547

Here's another option — it's not as clear, short, or efficient as using a named param, but I include it for completeness.

It's to pass fn outside the parens, just like the caller has to do.  I don't think you can do that directly, but you can wrap the call to fn like this:

fun SomeClass.foo(vararg x: String, fn: ((String) -> Unit)? = null): Result
    = fooBuilder(*x){ fn?.invoke(it) }.build()

Upvotes: 0

Cililing
Cililing

Reputation: 4753

You have two options:

1) vararg should be last argument (but then you won't be able to use simplified lambda call)

2) use named params:

fun SomeClass.fooBuilder(vararg x: String, fn: ((String) -> Unit)? = null): Result.Builder = TODO()
fun SomeClass.foo(vararg x: String, fn: ((String) -> Unit)? = null): Result = fooBuilder(x = *x, fn = fn).build()

Error you got is very logical - how compiler can know when passing vararg argumnets is finished?

Upvotes: 1

Karol Lewandowski
Karol Lewandowski

Reputation: 986

Any parameters that come after vararg have to be passed as a named parameter. Try it:

fun SomeClass.fooBuilder(vararg x: String, fn: ((String) -> Unit)? = null): Result.Builder = TODO()
fun SomeClass.foo(vararg x: String, fn: ((String) -> Unit)? = null): Result = fooBuilder(*x, fn = fn).build() // here I used named param

// it should work now:
SomeClass().foo("x") { str -> println("Hello $str") }

Upvotes: 2

Related Questions