Further Scala: Implicit conversions
My attempts to learn scala continue…
Implicit conversions are a cool, if slightly unsettling (from a java programmers POV) scala feature. If I have an instance of one class, and I try and call a method on it which is defined in a different class, then if there’s an “implicit” method in scope which will convert between the two, scala will silently use it.
e.g.
scala> var x = 12
x: Int = 12
scala> x.substring(1,2)
<console>:9: error: value substring is not a member of Int
x.substring(1,2)
scala> implicit def foo(i:Int):String={i.toString}
foo: (i: Int)String
scala> 12.substring(1,2)
res10: java.lang.String = 2
WITCHCRAFT! BURN THE COMPILER!
This lends itself to a very very useful trick; the ability to enhance classes with additional methods. Say you had a java Map class, and you wanted the ability to merge it with another Map according to some sort of merge function on the values. You’d probably do it like this:
class MergeableMap implements Map{
public MergeableMap(Map delegate){
this.delegate = delegate
}
public Map merge(Map otherMap, ValueMergingFunction mergeFunction){
....
}
... delegate implementations of all Map methods here...
}
Trouble is, (a) writing all the delegate methods is tedious, and(b) every time you want to use it, you’ve got to do
MergeableMap m = new MergeableMap(myMapVariable)
m.merge(myOtherMap,...)
Implicits in scala make this a lot easier:
class MergeableMap[A, B](self: Map[A, B]) {
def merge(m1, merger): Map[A, B] = {
... implementation here...
}
}
implicit def map2mergeableMap[A,B](m:Map[A,B]):MergeableMap[A,B] = new MergeableMap(m)
myMap.merge(myOtherMap, myMergeFunction)
myMap.get(...)
there’s no need to implement the other delegate methods, since we can just call them on the original Map class – but when we call merge() compiler-based voodoo works out that we want a mergeable map, and swaps it in for us. Magical.
Colin Yates
This is so much nicer than Groovy’s dynamic methods. I wonder if it is faster at run-time….
12 Jun 2011, 10:53
Chris May
I tried to test that, but found an interesting result…
- 6 seconds
-1 min 26 seconds
I don’t suppose that overhead is all down to metaclass fiddling. Someone with time to kill could make a proper benchmark that pre-compiles code and runs a large number of iterations of method calls with and without enriched classes in both langugages, and look at the difference. If that test is at all representative, though, I don’t think that the time taken to inject a new method is going to be the critical component in a groovy vs. scala performance shootout.
13 Jun 2011, 15:54
Add a comment
You are not allowed to comment on this entry as it has restricted commenting permissions.