Apparently this is going to be addressed in Scala 2.8, but until then there’s an annoying little detail when dealing with Java libraries (in my case, Wicket), from Scala. That being that methods requiring java.util.List types cannot be called with scala.List types.
The offending code:
val issues = List( 1, 2, 3 ) new org.apache.wicket.markup.html.list.ListView(wicketId, issues) {...
Causes this compilation error:
error: overloaded method constructor ListView with alternatives (java.lang.String,java.util.List[T])org.apache.wicket.markup.html.list.ListView[T] (java.lang.String,org.apache.wicket.model.IModel[java.util.List[T]])org.apache.wicket.markup.html.list.ListView[T] cannot be applied to (String,List[String])
There is a collection of implicit conversion functions for going from java.util.List to scala.List in the scala.collection.jcl.Conversions object, but not go go the other way around. These functions look like:
object Conversions { implicit def convertSet[T](set : java.util.Set[T]) = Set(set) implicit def convertList[T](set : java.util.List[T]) = Buffer(set) implicit def convertSortedSet[T](set : java.util.SortedSet[T]) = SortedSet(set) implicit def convertMap[T,E](set : java.util.Map[T,E]) = Map(set) implicit def convertSortedMap[T,E](set : java.util.SortedMap[T,E]) = SortedMap(set)</code> implicit def unconvertSet[T](set : SetWrapper[T]) = set.underlying implicit def unconvertCollection[T](set : CollectionWrapper[T]) = set.underlying implicit def unconvertList[T](set : BufferWrapper[T]) = set.underlying implicit def unconvertSortedSet[T](set : SortedSetWrapper[T]) = set.underlying implicit def unconvertMap[T,E](set : MapWrapper[T,E]) = set.underlying implicit def unconvertSortedMap[T,E](set : SortedMapWrapper[T,E]) = set.underlying }
With some friendly advice, I created the following conversion functions to do the conversion, including 2-dimensional (lists of lists) lists.
implicit def convertScalaListToJavaList(aList:List[String]) = java.util.Arrays.asList(aList.toArray: _*) implicit def convertScalaListListToJavaList(aList:List[List[String]]) = java.util.Arrays.asList(aList.toArray: _*)
The obscure notation (aList.toArray: _*
) is required as described in section 8.8 Repeated Parameters page 188 of the Programming in Scala book:
“This notation tells the compiler to pass each element of arr as its own argument to echo, rather than all of it as a single argument.”
and in 4.6.2 Repeated Parameters in The Scala Language Specification Version 2.7:
Furthermore, assume the definition:
def sum(args: Int*)
val xs = List(1, 2, 3)
The following applications method sum is ill-formed:
sum(xs) // ***** error: expected: Int, found: List[Int]
By contrast, the following application is well formed and yields again the result 6:
sum(xs: _*)
To cut the story short, it is required because the asList
method accepts variable number of object arguments, but we are passing in a single list object. The : _*
tells the compiler to instead pass in each element of the list individually, so that it looks like varargs. And as suggested by someone on the channel, it is consistent, if obscure, notation. When you read it, keep in mind that variableName: ObjectType
is normal notation in Scala for specifying the type of a declared parameter. So instead of a concrete type, we are specifying “any” type ( ‘_’ ), “any” number of times ( ‘*’ ).
Not so bad eh? ;P
You must be logged in to post a comment.