Scala: How to create methods that take variable-arguments (varargs) fields

This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 5.7, “How to Scala create methods that take variable-arguments (varargs) fields.”

Problem

To make a Scala method more flexible, you want to define a method parameter that can take a variable number of arguments, i.e., a varargs field.

Solution

Define a varargs field in your method declaration by adding a * character after the field type:

def printAll(strings: String*) {
  strings.foreach(println)
}

Given that method declaration, the printAll method can be called with zero or more parameters:

// these all work
printAll()
printAll("foo")
printAll("foo", "bar")
printAll("foo", "bar", "baz")

Use _* to adapt a sequence

As shown in the following example, you can use Scala’s _* operator to adapt a sequence (Array, List, Seq, Vector, etc.) so it can be used as an argument for a varargs field:

// a sequence of strings
val fruits = List("apple", "banana", "cherry")

// pass the sequence to the varargs field
printAll(fruits: _*)

If you come from a Unix background, it may be helpful to think of _* as a “splat” operator. This operator tells the compiler to pass each element of the sequence to printAll as a separate argument, instead of passing fruits as a single argument.

This is also similar to using xargs on the Unix/Linux command line.

Discussion

When declaring that a method has a field that can contain a variable number of arguments, the varargs field must be the last field in the method signature. Attempting to define a field in a method signature after a varargs field is an error:

scala> def printAll(strings: String*, i: Int) {
     |     strings.foreach(println)
     | }
<console>:7: error: *-parameter must come last
       def printAll(strings: String*, i: Int) {
                    ^

As an implication of that rule, a method can have only one varargs field.

As demonstrated in the Solution, if a field is a varargs field, you don’t have to supply any arguments for it. For instance, in a method that has only one varargs field, you can call it with no arguments:

scala> def printAll(numbers: Int*) {
     |     numbers.foreach(println)
     | }
printAll: (numbers: Int*)Unit

scala> printAll()

This case reveals some of the inner workings of how Scala handles varargs fields. By defining a varargs method that can take multiple integers, and then calling that method (a) with arguments, and (b) without arguments, you can see how Scala handles the two situations:

def printAll(numbers: Int*) {
    println(numbers.getClass)
}

scala> printAll(1, 2, 3)
class scala.collection.mutable.WrappedArray$ofInt

scala> printAll()
class scala.collection.immutable.Nil$

While the first situation reveals how Scala handles the normal “one or more arguments” situation, treating the “no args” situation as a Nil$ in the second situation keeps your code from throwing a NullPointerException.

Although the resulting types are different, as a practical matter, this isn’t too important. You’ll typically use a loop inside a method to handle a varargs field, and either of the following examples work fine whether the method is called with zero or multiple parameters:

// version 1
def printAll(numbers: Int*) {
    numbers.foreach(println)
}

// version 2
def printAll(numbers: Int*) {
    for (i <- numbers) println
}