Kotlin: Can you use named arguments for varargs?
Asked Answered
I

7

40

For example, you might have function with a complicated signature and varargs:

fun complicated(easy: Boolean = false, hard: Boolean = true, vararg numbers: Int)

It would make sense that you should be able to call this function like so:

complicated(numbers = 1, 2, 3, 4, 5)

Unfortunately the compiler doesn't allow this.

Is it possible to use named arguments for varargs? Are there any clever workarounds?

Indestructible answered 14/8, 2016 at 9:54 Comment(0)
R
38

It can be worked around by moving optional arguments after the vararg:

fun complicated(vararg numbers: Int, easy: Boolean = false, hard: Boolean = true) = {}

Then it can be called like this:

complicated(1, 2, 3, 4, 5)
complicated(1, 2, 3, hard = true)
complicated(1, easy = true)

Note that trailing optional params need to be always passed with name. This won't compile:

complicated(1, 2, 3, 4, true, true) // compile error

Another option is to spare vararg sugar for explicit array param:

fun complicated(easy: Boolean = false, hard: Boolean = true, numbers: IntArray) = {}

complicated(numbers = intArrayOf(1, 2, 3, 4, 5))
Raspings answered 14/8, 2016 at 10:19 Comment(1)
Changing the signature is not nice to users of the function. By tradition vararg is last, and it can lead to problems when you want just call it normally as you pointed out; numbers = *intArrayOf(...) is the way to go here.Bailey
C
37

To pass a named argument to a vararg parameter, use the spread operator:

complicated(numbers = *intArrayOf(1, 2, 3, 4, 5))
Champlain answered 14/8, 2016 at 10:36 Comment(1)
Using the spread operator with a named argument renders the spread operator redundant.Daloris
C
9

Kotlin Docs says clearly that:

Variable number of arguments (Varargs)

A parameter of a function (normally the last one) may be marked with vararg modifier:

fun <T> asList(vararg ts: T): List<T> {
  val result = ArrayList<T>()
  for (t in ts) // ts is an Array
    result.add(t)
  return result
}

allowing a variable number of arguments to be passed to the function:

  val list = asList(1, 2, 3)

Inside a function a vararg-parameter of type T is visible as an array of T, i.e. the ts variable in the example above has type Array<out T>.

Only one parameter may be marked as vararg. If a vararg parameter is not the last one in the list, values for the following parameters can be passed using the named argument syntax, or, if the parameter has a function type, by passing a lambda outside parentheses.

When we call a vararg-function, we can pass arguments one-by-one, e.g. asList(1, 2, 3), or, if we already have an array and want to pass its contents to the function, we use the spread operator (prefix the array with *):

val a = arrayOf(1, 2, 3)
val list = asList(-1, 0, *a, 4)

From: https://kotlinlang.org/docs/reference/functions.html#variable-number-of-arguments-varargs

To resume, you can make it using spread operator so it would look like:

complicated(numbers = *intArrayOf(1, 2, 3, 4, 5))

Hope it will help

Catholic answered 14/8, 2016 at 14:43 Comment(0)
D
3

The vararg parameter can be anywhere in the list of parameters. See example below of how it may be called with different set of parameters. BTW any call can also provide lambda after closed parenthesis.

fun varargs(
  first: Double = 0.0,
  second: String = "2nd",
  vararg varargs: Int,
  third: String = "3rd",
  lambda: ()->Unit = {}
) {
  ...
}

fun main(args: Array<String>) {
  val list = intArrayOf(1, 2, 3)

  varargs(1.0, "...", *list, third="third")
  varargs(1.0, "...", *list)
  varargs(1.0, varargs= *list, third="third")
  varargs(varargs= *list, third="third")
  varargs(varargs= *list, third="third", second="...")
  varargs(varargs= *list, second="...")

  varargs(1.0, "...", 1, 2, 3, third="third")
  varargs(1.0, "...", 1, 2, 3)
  varargs(1.0)

  varargs(1.0, "...", third="third")
  varargs(1.0, third="third")
  varargs(third="third")
}
Doorbell answered 20/2, 2018 at 5:5 Comment(0)
E
2

You can call your function with vararg like this:

complicated(numbers = intArrayOf(1, 2, 3, 4, 5))

The spread (*) operator is redundant.

Entrench answered 20/9, 2023 at 14:34 Comment(0)
R
0

below is a sample code for adding named argument for a varargs with custom string value

<string name="some_text">Some text with  custom value %1$s</string>


Text(
      modifier = modifier.padding(top = 24.dp),
      text = stringResource(
              id = R.string.some_text)
                .format(args = arrayOf("String value")),
        )
Rosalba answered 12/6, 2023 at 5:21 Comment(0)
C
-1

If the vararg argument is positional, with no default value, I found the best way to implement this is to have the first argument be your vararg argument. for example:

// define function like so
fun complicated(
    vararg numbers: Int, 
    easy: Boolean = false, 
    hard: Boolean = true
) { /* Do something */}

// then call function like so
complicated(1, 2, 3, 4, 5, easy = true)

Creswell answered 13/3, 2023 at 13:41 Comment(1)
This is a duplicate of the first part of @Vadzim's answer, where they suggest moving the optional arguments after the vararg.Brokenhearted

© 2022 - 2024 — McMap. All rights reserved.