Wednesday, December 24, 2014

Two tips for Java and Scala interoperability


I'm writing more and more Scala these days but don't want to give up on Java libraries I know and love. To this end, I've been writing ScalaTests with Mockito. It's fairly straightforward but two things initially foxed me.

Varargs

The first were varargs. "Both java and scala have varargs" but calling a Java method using varargs from Scala is not obvious.

I had code that looked like:

val x: List[X]       = ...
val ordered: InOrder = Mockito.inOrder(x)

which didn't compile because x was just being treated like an Object rather than an array of them.

The solution looks like this:

val ordered: InOrder = Mockito.inOrder(x:_*)


Conversions between Java and Scala collections

This is solved with a simple import.

import collection.JavaConversions._

Now we can do things like:

Thread.getAllStackTraces.map(x => println(x._1 + ":\n" + (x._2.mkString("\n    "))))

to print out all the stack traces of all the threads currently running. Without this import, the map function would fail as getAllStackTraces returns Map<Thread, StackTracesElement[]> - a Java Map that doesn't have the map method.

Sunday, December 14, 2014

Some useful Scala I learned this week


1. Indexes of a collection

If you want to  traverse a list of elements keeping the index in mind, you could do this with a fold but a more elegant way is something like:

    val words = List("the", "quick", "brown", "fox", "jumped", "over", "the", "lazy", "dog")

    words.zipWithIndex // returns tuples like (word, index)

2. Choosing only some elements of a collection

Now, let's say we want the tuples of those words that begin with 't'. We do this with the collect function in TraversableLike.

    words.zipWithIndex collect {
        case (word, index) if word.startsWith("t") => (word, index)
    }

(You will note that we pass collect a partial function). This will return the list:

List((the,0), (the,6))

That is, the 0th and 6th words begin with 't', and they are both 'the'.

3. Counting the elements that meet a criteria

is very simple:

    words count (_ startsWith("t"))

Will, unsurprisingly, return 2 for the above collection.


What I learned this week is that you could do all these with folds etc but Scala (I am told) has methods that do pretty much anything you could want. It's just a matter of learning them.

Scala's way of overriding final Java classes


Or "pimp my library".

I was pair programming with a Scala guru when he saw me creating a function to interrogate a String. He took my code and re-wrote as  something like this:

object MyImplicits {
  
  implicit class MyString(val string: String) {
    
      def startsWithD: Boolean = string.startsWith("D")
      
  }

}

object MyImplicitsMain {
  
  import com.phenry.scala.MyImplicits._
  
  def main(args: Array[String]) = {
    val aString = "Does this start with D?"
    println(aString.startsWithD) // this returns true
  }
  
}

So, effectively he added a function to the String class for any code that imports this implicit.

Note that implicits can live in objects and packages (as they basically hold what Java programmers would recognise as statics) but not class or traits.

One is advised to be careful with implicits, however. "Implicits are very powerful but you should use them with care," said Scala's creator.