Remedial Scala : Repeated Parameters and Initializing Collections
I only recently began to learn Scala (rooscaloo is coming along nicely, btw). I’m having a great time and the scala-user mailing list has been a great resource for learning more idiomatic ways to express myself in Scala. Every couple of days I ask a dumb question which ends up teaching me a lot about the language. So I figured I’d write about what I learn, even if it’s at a much lower plane of existence than a lot of other Scala commentary that’s out there. Hopefully another neophyte may someday find this informative.
Repeated Parameters
Today’s lesson is about two things that I didn’t initially know were related. First, I wanted to know how to initialize a map with a list of pairs. The Scala Map constructor take a variable list of pairs (a repeated parameter) to initialize the map. For example:
scala> val map = Map((1, 2), (3, 4)) map: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2, 3 -> 4)
But, I have a list of pairs, not a parameter list. So, here’s what I was doing:
val map = Map() ++ listOfPairs
which worked fine. Basically, it takes an empty map and adds the pairs in the list. It smells a little though and I was sure this wasn’t idiomatic. So I asked. The correct answer is the _* operator of course:
scala> val args = List((1, 2), (3, 4)) args: List[(Int, Int)] = List((1,2), (3,4)) scala> val map = Map(args : _*) map: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2, 3 -> 4)
When a parameter is followed by “: _*”, this tells Scala to expand the argument to a variable argument list rather than a single argument. Funny enough, I actually knew this from chapter 8 of the Programming in Scala book, but sometimes I forget things…
So, this explains why all of the Scala collection types take just a repeated parameter list for initialization rather than another collection like the Java collections library.
Turning an Option into a Set
The revelation above led directly to the solution for my other problem. In particular, I wanted a nice way to convert an Option (think of it as a collection with exactly 0 or 1 elements) to a Set. I had this code:
def toSet[T](o : Option[T]) : Set[T] = {
o match {
case Some(some) => Set(some)
case None => Set()
}
}
which works fine, but …
It turns out that Option has a toList method so I can pass it to a repeated parameter list to initialize a collection from an Option:
scala> val s = Set(Some(1).toList : _*) s: scala.collection.immutable.Set[Int] = Set(1)
and:
scala> val s = Set(None.toList : _*) s: scala.collection.immutable.Set[Nothing] = Set()
Pretty cool … Ok, so it isn’t exactly pretty and I stayed with my utility function just for readability, but it’s nice when a language has this kind of consistency where the solution to one problem crops up over and over again.
Remedial, eh?