Scala Dynamic Proxy

0 comments

One of the coolest features since Scala 2.10.3 are the Scala dynamic types. Let's look at what they are! A dynamic type is a type with which we can dynamically add fields / methods to an existing type. This is better explained with some examples Assume that we have a scala class as defined below:

  class MyClass {
    def myMethod(str: String) = println(str)
  }
  ...
  ...
  val myClass1 = new MyClass().myMethod("printme") // Fine!
  val myClass2 = new MyClass().notMyMethod("beep") // Yes you know it!
For situations like above, scala dynamic types come to the rescue. They are a mechanism by which we can intercept calls to a non-existing field or a method in a class Let's now modify our MyClass and try to get rind of the compile error when invoking the notMyMethod!
  import scala.language.dynamics
 
  object MyClass extends Dynamic {
 
    private var myMap = mutable.Map[String, Any]()
   
    def myMethod(str: String) = println(str)
   
    def selectDynamic(args: String) = println("selectDynamic " + args)
   
    def applyDynamic(methodName: String)(args: Any*) = println("applyDynamic " + args)
   
    def applyDynamicNamed(methodName: String)(args: (String, Any)*) = println("applyDynamicNamed " + args)
   
    def updateDynamic(name: String)(value: Any) = { myMap(name) = value } // mutating sounds scary!!!
  }
Let's go through each one of those xxxDynamic methods that we added in the example above:
  • applyDynamic - Dynamically creates a method and the arguments as though that method was part of the declared type
  • applyDynamicNamed - Similar to applyDynamic, with the benefit that we can use a named argument
  • selectDynamic - Dynamically invoke a field as though that field was part of the given type (think of a getter)
  • updateDynamic - Dynamically update a field as though that field was part of the given type - (think of a setter)
I wonder why there is the updateDynamic, I would rather refrain from using it for obvious reasons that we all know (avoid mutability damn it!) Try the following examples and figure out which xxxDynamic method is invoked in each case
MyClass.showMyAge("my age is", 34) - ???
MyClass.FUCK!! - ???
MyClass.printUser(userName = "Joe", age = "34")  - ???
MyClass
If you have got all the above examples correctly, you have understood the basics of Scala's dynamic types!

Converting collections to and fro in Scala / Java

0 comments

Say that you have to use a Java library in your Scala application and this Java library has a couple of API's that require you to pass a Java collection type. Let's see how we can cope with it by looking at the following examples: Suppose I have a java ArrayList that contains some Integers and I want to map these List of Integers by incrementing 1 to each of the elements in the ArrayList as below:

scala> val javaList = new java.util.ArrayList[Integer]()
javaList: java.util.ArrayList[Integer] = []

scala> javaList.add(1)
res0: Boolean = true

scala> javaList.add(2)
res1: Boolean = true

scala> javaList map { i => i + 1 }
error: value map is not a member of java.util.ArrayList[Integer]
    javaList map { i => i + 1 }

As you can see that the message from the Scala compiler is very clear that there is no map function available to the ArrayList and we need someway to tell the compiler to treat that as a Scala collection. Java Conversions to the rescue:

import scala.collection.JavaConversions._

scala> javaList map { i => i + 1 }
res3: scala.collection.mutable.Buffer[Int] = ArrayBuffer(2, 3)

What happened above is that we imported the JavaConversions package available in the Scala library to tell the compiler that it should implicitly convert the java.util.ArrayList to a closest possible collection type in Scala which in our case happened to be an ArrayBuffer. If you take a look at the Scala API documentation on JavaConversions there is an implicit method called asScalaBuffer which was used in our example implicitly to convert the java.util.ArrayList to a Scala collection type.

The JavaConversions package contains a couple of implicit methods to convert between a Java collection to a Scala collection and vice-versa. There is yet another package in the scala.collections called JavaConverters. What is the difference? Both the JavaConversions and JavaConverters do more or less the same thing, i.e., convert to and fro between a Java / Scala collection. You might be wondering over which one you should prefer. Let's find that out with the help of some more examples:

scala> val scalaMap = Map("A" -> 1)
scalaMap: scala.collection.immutable.Map[String,Int] = Map(A -> 1)

scala> scalaMap.contains(1)
error: type mismatch;
    found   : Int(1)
    required: String
    scalaMap.contains(1)
    ^

What we did just now is instantiated an immutable Map from the Scala library that maps a set of String to Int. Remember, the syntax for Scala Map looks like below:

trait Map[A, +B] extends Iterable[(A, B)] with GenMap[A, B]
    with MapLike[A, B, Map[A, B]]

The contains method looks like below:

def contains(key: A): Boolean

What we did with our scalaMap variable above is that we created a Map that took a String as key and Int as value, so when we called the contains method and passed it an Int, it failed. The contains method implementation in Scala internally calls the get method to check if the key is contained in the collection. Now let's see what happens if we import the JavaConversions:

scala> import scala.collection.JavaConversions._
import scala.collection.JavaConversions._

scala> scalaMap.contains(1)
res1: Boolean = false

It kind of worked and returned false. Practically speaking the variable scalaMap does not contain 1, so returning false would look like the right thing to do. What was compromised here is the type safety that we had before importing the JavaConversions. Soon after importing the JavaConversions package, the Scala compiler gives an implicit call to the MapWrapper class wherein the MapWrapper class implements the containsKey method from the Java library and the implementation looks like this in the Scala library's MapWrapper class

    override def containsKey(key: AnyRef): Boolean = try {
    // Note: Subclass of collection.Map with specific key type may redirect generic
    // contains to specific contains, which will throw a ClassCastException if the
    // wrong type is passed. This is why we need a type cast to A inside a try/catch.
    underlying.contains(key.asInstanceOf[A])
    } catch {
        case ex: ClassCastException => false
    }

As it can be see, the containsKey takes an Object / AnyRef rather than the specific type which in our case is a String. With JavaConversions, we went down from a stricter type to a more looser type. Let's see now how we could retain the stricter type by being a bit more explicit, using the JavaConverters!

scala> val scalaMap = Map("A" -> 1)
scalaMap: scala.collection.immutable.Map[String,Int] = Map(A -> 1)

scala> import scala.collection.JavaConverters._
import scala.collection.JavaConverters._

scala> scalaMap.contains(1)
error: type mismatch;
    found   : Int(1)
    required: String
    scalaMap.contains(1)
    ^

Did you see the difference? There is now no implicit conversion between the Java and Scala collection types. If you want the scalaMap variable to be a java.util.Map, you now have to be explicit as below:

scala> scalaMap.asJava
res0: java.util.Map[String,Int] = {A=1}

So from my point of view, it is better to be explicit which would imply to use the JavaConverters instead of JavaConversions.