A lot of dynamically typed languages have function that catch-all all messages doesn't exists in the object. It gives these languages a lot of power to write DSL. With Scala, you have an opportunity to write DSLs in the same way. Learn why and how.
A lot of dynamic typed languages has function that catch all messages the target object doesn’t have. It gives these languages a lot of power to write DSL.
Scala 2.9 introduced an experimental option that enables this sort of dynamic handling of accesses to types in ways that would otherwise fail static type checking. It was refined and made non-experimental in 2.10, though it is still controlled through flag which is disabled by default.
Dynamic type allows you to access instance members that aren’t statically
defined in a class. It’s a marker trait with no members - it provides a hint to the compiler
to rewrite method calls and field accesses to missing members as calls to one of
the following methods:
selectDynamic- method allows to write field accessors
updateDynamic- method allows to write field updates
applyDynamic- method allows to call methods with arguments
applyDynamicNamed- method allows to call methods with named arguments
To shed more light on how these methods might work see examples below together with overview of dynamic translations that are done under the hood:
So what you should do if you want to add dynamic member lookup in your code?
It’s simple. You just need to write a class that extends
Dynamic trait. Inside this class you can implement any of these four methods.
But that is not all. As I mentioned above it’s disabled feature by default so you need to set the compiler option
-language:dynamics or add a
import scala.language.dynamics to make the feature work.
And that’s all you need to do to make your statically typed code more dynamic.
As an example, we might want to build our own
Map implementation. Our Map needs to do few things:
- store data as key-value, where key is String and value is Generic type,
- return default(defined) value for keys that doesn’t exists.
We can do it like this :
So now we can use it in this way:
How it works? I think, the code above is self-explanatory. Every time a message is sent to this object, it will try to find value with the key of a sent message in the included Map. If it doesn’t find any, it will return the value defined as default.
Dynamic you can also create your own custom builders…
Now you can build you own drinks in easy way:
Implicit conversions are applied before missing methods are passed into
applyDynamicNamed method. To prove that, Lets go back to first example.
When we call key that doesn’t exists, the MyMap return the value 150.
Let’s see what happens with implicit conversion in scope. First we define implicit class:
Import it in the file where we use our map, and try again to call method above.
Sadly, it does not work well together. Compiler doesn’t know which method it should apply if you chain methods as in the example above. So, you have to use dot as methods separator.