Working with Scala Futures

Working with scala Futures is excellent for performance and non-blocking program flow. However, some conversions are slightly more tedious.

To add a completion action to a future, two non-blocking options exist. First, the Future can utilize a onSuccess (or onFailure / onComplete) call as shown below:


import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global

val f1 = future {
Thread.sleep(10000)
println("Done")
}

f1 onSuccess {
case _ => println("After Done")
}

Second, the result (assumed successful) can be mapped to the next future result:


val f2 = future {
Thread.sleep(10000)
println("Done again, returning 1")
1
}

f2.map(number => println(10+number))

If a Seq of Futures is present, the result of all Futures may be relevant on how to proceed. This is where Future.sequence comes handy:


val futSeq = (1 to 10).map(i =>
future {
Thread.sleep(10000)
println("Done again, returning "+i)
i
}
)

val seqRes = Future.sequence(futSeq)
seqRes.map(s => println(s.sum))

Query XML with namespaces in Scala

When processing more complex XML, the notion of the namespaces as part of elements and attributes becomes increasingly important. In Scala, this is actually quite easy. Imagine the following XML:

import scala.xml._
val a = <a xmlns:ns1="www.ns1"><b/><b/><b/><ns1:b/></a>

A standard query would return simply all b elements:

a \ "b"
res0: scala.xml.NodeSeq = NodeSeq(<b xmlns:ns1="www.ns1"/>, <b xmlns:ns1="www.ns1"/>, <b xmlns:ns1="www.ns1"/>, <ns1:b xmlns:ns1="www.ns1"/>)

To query for the specific namespace, two options are possible. The first option:

a \ "b" filter (e => e.namespace == "www.ns1")

Another option is to use Scales (untested):

val ns = Namespace("www.ns1")
a.asScala \* ns("b")

Scala XML attribute parsing

I really like the Scala XML capabilities. However, the parsing of attributes requires some additional care. Consider the following example:

val data = <doc>
<entry id="myid1">
<text id="YYYYYYY">"A"</text>
</entry>
<entry id="myid2">
<text id="XXXXXXXX">"A"</text>
</entry>
</doc>

With the single backslash \ accessing the elements without traversing and the double backslash \\ traversing, access to all id elements seems feasible with the following code:

Console println data \ "entry" \ "@id"

Unfortunately, this call will not return the desired values. The reason is that the class of scala.xml.NodeSeq does contain the projection functions, but not the attribute function (which is part of scala.xml.Node). While this will work on single XML elements, in this case the Seq of elements prevents this access.

Console println (data \ "entry").getClass

Thus, the following lines will give all id’s of <entry> nodes:

(data \ "entry").foreach(Console println _ \ "@id")
Console println (data \ "entry").map(_ \ "@id")

Alternatively, if all id’s of sub-elements shall be included, the code becomes easier again:

Console println data \ "entry" \\ "@id"

Issues with Scala Tuples

After a while of diffing through Scala code and working a bit with it, some aspects appear less comforting about how tuples are realized.

Take the following example in Python:

>>> (text1, Text2) = ("aa", "bb")
>>> text1
'aa'
>>> Text2
'bb'

Easy and simple. The same in Scala:

scala> val (text1, Text2) = ("aa", "bb")
:7: error: not found: value Text2
       val (text1, Text2) = ("aa", "bb")

Yes, from an end-users perspective the “flexible” language does not allow you to name the values in a way you want. Naming the first letter uppercase throws an error. It seems the reason is pattern matching, as described here: Link to scala-lang.org.

Another part of tuples I find less straightforward is the access to the individual tuple elements in Scala:

scala> val tup = ("aa", "bb")
tup: (String, String) = (aa,bb)
scala> tup._1
res1: String = aa

Everything else in Scala seems to start with a zero-based index. As per Martin Oderski’s book, the reason for this is because Haskell and ML have this as naming convention. From an end-user perspective, this is one more “exception” from the rule a person has to remember. Why would you make such tradeoff’s when you don’t need to? It really seems like a missed opportunity for a new language to get some consistency in place… .

Tuples and Triples in Scala

In Java, to use a Tuple or even Triple as a key for a HashMap typically requires a custom class with custom hashCode and equals calls. Scala makes this quite easy and convenient:

object Main {
    def main(args: Array[String]): Unit = {
    	// create a map with a tuple as key
        var map = HashMap[(Int, String), String]()
        
        // add
        map.put((3, "A"), "Abc");
        map.put((3, "B"), "BBc");
        
        println(map)
        println("(3, \"A\").hC() ", (3, "A").hashCode())
        println("(3, \"B\").hC() ", (3, "B").hashCode())
        println("(3, \"A\")==(3, \"A\") ", (3, "A") == (3, "A"))
        println("(3, \"A\") == (3, \"B\") ", (3, "A") == (3, "B"))
        println("(3, \"A\").eq((3, \"A\")) ", (3, "A").equals((3, "A")))
        println("(3, \"A\").eq((3, \"B\")) ", (3, "A").equals((3, "B")))
        
        // and using Triple is the same
        var map2 = HashMap[(Int, Int, String), String]()
    }
}

Scala and MultiMap – first steps

After having a few run’s with Scala, I came across the MultiMap trait. Below an example that could represent a mapping of postcodes to their starting number, e.g. 3 as a key to all postcodes with 3.

import scala.collection.mutable.Set
import scala.collection.mutable.HashMap
import scala.collection.mutable.MultiMap

object Main {
    def main(args: Array[String]): Unit = {
        // data
        val set1 = Set(1, 11, 12, 13);
        val set1b = Set(111, 1111, 112, 113)

        // standard HashMap
        // add set, add second set
        val mymap = HashMap[Int, Set[Int]]()
        mymap.put(1, set1)
        mymap(1) ++= set1b // mymap(1) needs to exist!

        println("Std map, req 1: "+mymap.get(1))

        // with multimap
        var mm = new HashMap[Int, Set[Int]] with MultiMap[Int, Int]  
        set1.foreach(mm.addBinding(1, _))
        set1b.foreach(mm.addBinding(1, _))
        // or mm(1) ++= set1b if mm(1) exists

        println("Multi map, req 1: "+mm.get(1))
    }
}

Overall, the addBinding call removes the checking of the Set that would need to be in place for future additions. Neat.