Scala 2.10: class OhMy extends Dynamic !
The first part of the post is a bit like “someone is wrong on the internet!” (yeah, a rant), so feel free to skip it and dive into a detailed post about Scala’s new Dynamic type in part 2 of this post.
Part 1: The rant about a wrong example
I was meaning to write about upcoming Scala features but got sidetracked by work and GeeCON related stuff this week. I’ve just read a post about Dynamic on scala.net.pl and… It’s totally wrong! :< C’mon people – you’ve got scala _as_ your domain name, so at least run the examples in a REPL before you post something ;-)
-
val d = new Dynamic {}
-
d.bar = "bar" // THIS IS WRONG
Ok, so on the REPL – the first line will compile. Dynamic is in fact a new Trait in Scala 2.10 and you can create new instances of Traits (just as you could in Java with anonymous inner classes) using the new Trait {} syntax. Line 2 though, it utterly wrong. It will cause 2 compile time errors, namely:
-
scala> d.bar = "bar"
-
-
console :11: error: value selectDynamic is not a member of Dynamic
-
val $ires1 = d.bar
-
^
-
console: 8: error: value updateDynamic is not a member of Dynamic
-
d.bar = "bar"
Dynamic is NOT “a magic type you can set random stuff on”, it’s a bit more discrete. You can build such construct using Dynamic – sure, but that’s not all it is.
Part 2: A deep dive into Scala’s Dynamic type
Ok, end of rant and back to the basics. So… How do we use Dynamic? In fact, it’s used by implementing a few “magic” methods:
- applyDynamic
- applyDynamicNamed
- selectDynamic
- updateDynamic
Let’s take a look (with examples, at each of them. We’ll start with the most “typical one”, and move on to those which would allow the construct shown above (which didn’t (back then) compile) and make it work this time ;-)
applyDynamic
Ok, our first magic method looks like this:
-
object OhMy extends Dynamic {
-
def applyDynamic(methodName: String)(args: Any*) {
-
println(s"""| methodName: $methodName,
-
|args: ${args.mkString(",")}""".stripMargin)
-
}
-
}
-
-
OhMy.dynamicMethod("with", "some", 1337)
So the signature of applyDynamic takes the method name and it’s arguments. So obviously we’d have to access them by their order. Very nice for building up some strings etc. Our implementation will only print what we want to know about the method being called. Did it really get the values/method name we would exect? You can try it out (it’s copy paste ready) in your Scala 2.10.M3 REPL – if you don’t have one at hand: yeah, the output would be:
methodName: dynamicMethod, args: with,some,1337
By the way, did you know about RichString’s stripMargin? It’s a nice way to still have nicely printable strings when you’re using multiline strings. By default it trims everything that is before the | sign (from the left side, for each line). The sign can be overriden of course if you fancy $ signs for example… ;-)
applyDynamicNamed
Ok, that was easy. But it didn’t give us too much control over the names of the parameters.
Wouldn’t it be nice if we could just write JSON.node(nickname = “ktoso”)? Well… turns out we can!
-
object JSON extends Dynamic {
-
def applyDynamicNamed(name: String)(args: (String, Any)*) {
-
println(s"""Creating a $name, for:\n "${args.head._1}": "${args.head._2}" """)
-
}
-
}
-
-
JSON.node(nickname = "ktoso")
So this time instead of just a list of values, we also get their names. Thanks to this the response for this example will be:
Creating a node, for: "nickname": "ktoso"
I can easily imagine some pretty slick DLSs being built around this!
selectDynamic
Not it’s time for the more “unusual” methods. apply methods we’re pretty easy to understand. It’s just a method with some arbitrary name. But hey, isn’t almost everything in scala a method – or we can have a method on an object that would act as a field? Yeah, so let’s give it a try! We’ll use the example with applyDynamic here, and try to act like it has a method without ():
-
OhMy.name // fails
Hey! Why didn’t this work with applyDynamic? Yeah, you figured it out already I guess. Such methods (without ()) are treated special, as they would usualy represent fields for example. applyDynamic won’t trigger on such calls. Let’s add selectDynamic to the mix then, shall we?
-
object HasStuff extends Dynamic {
-
def selectDynamic(name: String): String = s"I have $name!"
-
}
And this time when we execute HasStuff.bananas we’ll get “I have bananas!” as expected. Notice that here we return a value instead of printing it. It’s because it “acts as a field” this time around. But we could also return things (of arbitrary types) from any other method described here (applyDynamic could return the string instead of printing it).
updateDynamic
What’s left you ask? Ask yourself the following question then: “Since I can act like a Dynamic object has some value in some field… What else should I be able to do with it?” The answer is obviously: “set it”! That’s what updateDynamic is used for. There is one special rule about updateDynamic though – it’s only valid if you also took care about selectDynamic – that’s why in the first example the code generated errors about both – select and update. For example if we’d implement only updateDynamic, we would get an error that selectDynamic was not implemented and it wouldn’t compile anyway. It makes sense in terms of plain semantics if you think about it.
When we’re done with this example, we can actually make the (wrong) code from the first code snippet work. The bellow snippet will be an implementation of what was shown on the first snippet on that other website, and this time it’ll actually work ;-)
-
object MagicBox extends Dynamic {
-
private var box = mutable.Map[String, Any]()
-
-
def updateDynamic(name: String)(value: Any) { box(name) = value }
-
def selectDynamic(name: String) = box(name)
-
}
Using this Dynamic “MagicBox” we can store items at arbitrary “fields” (well, they do seem like fields, even though they are not ;-)). An example run might look like:
scala> MagicBox.banana = "banana" MagicBox.banana: Any = banana scala> MagicBox.banana res7: Any = banana scala> MagicBox.unknown java.util.NoSuchElementException: key not found: unknown
By the way… are you curious how Dynamic [source code] is implemented? The fun part here is that the trait Dynamic, does absolutely nothing by itself – it’s “empty”, just a marker interface, like in the good ol’ Serializable days ;-) Obviously all the heavylifting is done by the compiler here.
Anyway, thanks for reading and… don’t overuse Dynamic, will ya? :-)
Tags: 2.10, dynamic, scala, tips, type, update

















