Scala varags handling
Mainly for my future reference, a quick overview of how Scala appears to handle varargs. The Scala book doesn’t offer an explanation currently so this is all derived through experiments using Scala 2.6.1.
To make a method accept a variable number of arguments, it is defined as follows.
scala> def foo(s: String*) { println(s) }
foo: (String*)Unit
Like Java, Scala requires the vararg to be the last parameter to the function. Once in your method, the parameter is of type Array[String] (more generally Array[A] where A is a type parameter).
scala> def foo(s: String) { println(s) }
foo: (String)Unit
scala> foo("hello")
hello
scala> def foo(s: String*) { println(s) }
foo: (String*)Unit
scala> foo("hello", "world")
Array(hello, world)
scala> def foo(s: String*, t: Int) { println(s) }
:4: error: *-parameter must come last
def foo(s: String*, t: Int) { println(s) }
^
Unlike Java 1.5, you must explicitly declare your functions to accept variable arguments, you can not declare a parameter to be an Array[A] and have the runtime perform an automatic conversion for you (I believe this may have something to do with Java 13/1.4 compatibility). So the following is not equivalent to the above and will not compile:
scala> def foo(s: Array[String]) { println(s) }
foo: (Array[String])Unit
scala> foo("hello", "world")
:6: error: wrong number of arguments for method foo: (Array[String])Unit
foo("hello", "world")
^
Likewise, you can not declare something to take a varargs parameter and call it as if it’s an array (as you can in Java):
scala> def foo(s: String*) { println(s) }
foo: (String*)Unit
scala> foo(Array("hello", "world"))
:6: error: no type parameters for method apply: (A*)Array[A] in object Array exist so that it can be applied to arguments (java.lang.String,java.lang.String)
--- because ---
result type Array[A] is incompatible with expected type String
foo(Array("hello", "world"))
^
There’s also some odd rules around overloading of functions, due to erasure:
scala> object Foo { def foo(ss: String*) = println(ss); def foo(is: Int*) = println(is) }
:4: error: double definition:
method foo:(Int*)Unit and
method foo:(String*)Unit at line 4
have same type after erasure: (Seq)Unit
object Foo { def foo(ss: String*) = println(ss); def foo(is: Int*) = println(is) }
The variable argument gets the type Seq[A] (the actual underlying runtime type is Array[A]), and owing to the wonderful properties of erasure, both these methods have the same signature.
Not really related, but it would be nice if the book/docs were in plain(ish) HTML form. I kind of cuss under my breath each time I click on a PDF link (although on OSX its not so bad).
Michael Neale
22 Jan 08 at 1:08 pm
Yeah, I see no reason why “the book” for example cannot be produced in HTML also, from what I’ve gleaned about their build process would seem to be doable. I don’t mind PDFs though, Preview in Leopard is much better and very fast, so it’s quite good for looking up terms such as “varargs”, etc. Makes it easy to spot mistakes/oversights also.
Tom Adams
22 Jan 08 at 8:26 pm