This should be an obvious one but I've not yet found an elegant solution. For various reasons, I need to create an immutable Scala map (scala.collection.immutable.Map from Scala 2.10), but I can only write Java code. How do I do this?
2 Answers
Wild guess - here goes nothing:
scala.collection.immutable.Map$.MODULE$.<…, …>empty()
6 Comments
MODULE by hand? As far as I know there are forwarder static methods that already do this. Can't check right now though, I have no compiler at hand.Map$ instead of Map but accessing MODULE$ by hand is unnecessary.scala.collection.immutable.Map$.MODULE$.<String, String>empty();At first I was puzzled that just doing the following would fail:
scala.collection.immutable.Map<Integer, String> = scala.collection.immutable.Map$.<Integer, String>empty();
The reason it seemed odd is because I know for a fact that scala generates static forwarders that internally dereference MODULE$ and call the corresponding (non-static) method.
I made some tests, and although what I found is somewhat tangential to the original question, it is still related and good to know.
Say we have the following:
package test
object MyScalaObject {
def empty[A, B]: Map[A, B] = sys.error("TODO")
}
Using javap we can see that a static forwarder is generated:
public class test.MyScalaObject extends java.lang.Object{
public static scala.collection.immutable.Map empty();
public test.MyScalaObject();
}
And indeed we can in java just do the following:
scala.collection.immutable.Map<Integer, String> myMap = test.MyScalaObject.<Integer, String>empty();
All is well and nice.
However, if we add a class or trait MyScalaObject that also defines a method with the same signature, no static forwarder is generated by scala (certainly because the JVM does not allow a class to define both a static and non-static method with the same signature). There are probably other different subtle situations that prevent the static forwarders to be generated.
Consider:
package test
class MyScalaObject {
def empty[A, B]: Map[A, B] = sys.error("TODO")
}
object MyScalaObject {
def empty[A, B]: Map[A, B] = sys.error("TODO TOO")
}
javap shows that the static forwarder has indeed disappeared:
public class test.MyScalaObject extends java.lang.Object{
public scala.collection.immutable.Map empty();
public test.MyScalaObject();
}
In this case it means that we have to explictly dereference $MODULE which points to the (unique) instance of the singleton object:
scala.collection.immutable.Map<Integer, String> myMap = test.MyScalaObject$.MODULE$.<Integer, String>empty();
As it turns out, both the trait scala.collection.immutable.Map and its companion object define a parameterless empty method, so we stumble upon this very issue.
The moral is that while static forwarders are a potentially useful feature, it is also very fragile because the mere fact of modifying a class (in this case adding an empty method in class MyScalaObject) can break the feature, without even touching its companion object itself. It is thus certainly a good idea to always explicitly reference MODULE$ (as in Wilfred Springer's answer) even if it looks less nice and even if the static forwarder is currently present, to prevent potential breakage when updating to a newer version of the library.