Varargs

Many programming languages have the concept of “varargs”: parameters declared for a method or function that represent zero, one, or several values.

In Java, we use ... syntax:

void something(String... lots) {
  if (lots.size>0) {
    // do something
  }
}

lots is treated as a Java array, in this case an array of String objects.

JavaScript just dumps everything not matched by named parameters into an arguments array:

function something() {
  if (arguments.length>0) {
    // do something
  }
}

Ruby uses * syntax:

def something(*lots)
  if lots.length > 2
    # do something
  end
end

Kotlin dedicates the vararg keyword to this role:

fun main() {
  reciprocate(1, 2, 3, 5, 7)
}

fun reciprocate(vararg values: Int) {
  values
    .map { 1.0 / it }
    .forEach { println(it) }
}

Here, reciprocate() can accept zero parameters, one parameter, or many parameters. We assign the vararg a name (values), and the parameters are given to us in the form of an Array. Here, we use the same code as in the previous section to compute the reciprocal of each of those values and print them to the console.

What You Can Pass In

Typically, a vararg parameter has values passed in via a comma-delimited list (e.g., reciprocate(1, 2, 3, 5, 7)). Those do not have to be constants, though:

fun main() {
  val foo = 1
  val bar = 2
  val goo = 3
  val baz = 5
  val heyWhatComesAfterBaz = 7

  reciprocate(foo, bar, goo, baz, heyWhatComesAfterBaz)
}

fun reciprocate(vararg values: Int) {
  values
    .map { 1.0 / it }
    .forEach { println(it) }
}

Any expression, including simple variable references, can be supplied for values.

In addition, Kotlin offers special support for an existing Array. If you already have an Array with the values that you want to supply, but the function that you are calling uses vararg (instead of an Array parameter), you can use the “spread operator”:

fun main() {
  val things = arrayOf("foo", "bar", "goo")

  capped(*things).forEach { println(it) }
}

fun capped(vararg strings: String) = strings.map { it.toUpperCase() }

Here, our capped() function takes a vararg of String values and returns them capitalized. We have an Array of String values in the form of things. We can pass things to capped() by prefixing things with *. This basically says “take the contents of this array and add them each as individual parameters to the function call”.

Since we happened to write capped(), it would be simpler to just have capped take an Array parameter. If capped() were written by somebody else, though, and they chose to use vararg, then the spread operator still lets us use our Array.

Things get a bit strange with types that map to primitives, though. vararg expects the dedicated array types to be used with the spread operator. So, in the following example, the reciprocate() function takes a vararg of Int. For the spread operator to work, we need to use an IntArray, not a regular Array:

fun main() {
  val primes = intArrayOf(1, 2, 3, 5, 7)

  reciprocate(*primes)
}

fun reciprocate(vararg values: Int) {
  values
    .map { 1.0 / it }
    .forEach { println(it) }
}

Prev Table of Contents Next

This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.