What does param: _* mean in Scala?
ScalaSyntaxScala CollectionsScala Problem Overview
Being new to Scala (2.9.1), I have a List[Event]
and would like to copy it into a Queue[Event]
, but the following Syntax yields a Queue[List[Event]]
instead:
val eventQueue = Queue(events)
For some reason, the following works:
val eventQueue = Queue(events : _*)
But I would like to understand what it does, and why it works? I already looked at the signature of the Queue.apply
function:
def apply[A](elems: A*)
And I understand why the first attempt doesn't work, but what's the meaning of the second one? What is :
, and _*
in this case, and why doesn't the apply
function just take an Iterable[A]
?
Scala Solutions
Solution 1 - Scala
a: A
is type ascription; see https://stackoverflow.com/questions/2087250/what-is-the-purpose-of-type-ascription-in-scala
: _*
is a special instance of type ascription which tells the compiler to treat a single argument of a sequence type as a variable argument sequence, i.e. varargs.
It is completely valid to create a Queue
using Queue.apply
that has a single element which is a sequence or iterable, so this is exactly what happens when you give a single Iterable[A]
.
Solution 2 - Scala
This is a special notation that tells the compiler to pass each element as its own argument, rather than all of it as a single argument. See here.
It is a type annotation that indicates a sequence argument and is mentioned as an "exception" to the general rule in section 4.6.2 of the language spec, "Repeated Parameters".
It is useful when a function takes a variable number of arguments, e.g. a function such as def sum(args: Int*)
, which can be invoked as sum(1)
, sum(1,2)
etc. If you have a list such as xs = List(1,2,3)
, you can't pass xs
itself, because it is a List
rather than an Int
, but you can pass its elements using sum(xs: _*)
.
Solution 3 - Scala
For Python folks:
Scala's _*
operator is more or less the equivalent of Python's *-operator.
Example
Converting the scala example from the link provided by Luigi Plinge:
def echo(args: String*) =
for (arg <- args) println(arg)
val arr = Array("What's", "up", "doc?")
echo(arr: _*)
to Python would look like:
def echo(*args):
for arg in args:
print "%s" % arg
arr = ["What's", "up", "doc?"]
echo(*arr)
and both give the following output:
> What's
> up
> doc?
The Difference: unpacking positional parameters
While Python's *
-operator can also deal with unpacking of positional parameters/parameters for fixed-arity functions:
def multiply (x, y):
return x * y
operands = (2, 4)
multiply(*operands)
> 8
Doing the same with Scala:
def multiply(x:Int, y:Int) = {
x * y;
}
val operands = (2, 4)
multiply (operands : _*)
will fail:
> not enough arguments for method multiply: (x: Int, y: Int)Int.
> Unspecified value parameter y.
But it is possible to achieve the same with scala:
def multiply(x:Int, y:Int) = {
x*y;
}
val operands = (2, 4)
multiply _ tupled operands
According to Lorrin Nelson this is how it works:
> The first part, f _, is the syntax for a partially applied function in which none of the arguments have been specified. This works as a mechanism to get a hold of the function object. tupled returns a new function which of arity-1 that takes a single arity-n tuple.
Futher reading: