Following up from my post on Deconstructing the map literal in Scala, I thought it might be fun to go the other way around, and create a few literals of own. Since Scala provides the language features to enable literal-like syntax, and not the actual literals themselves, we can do a lot of stuff to reduce the amount of typing we have to.
In your production code, you probably wouldn’t use a lot of literals, regardless of language support. However, in test cases, they are much more common. If creating objects in your tests becomes easier, you will tend to write better tests.
Suppose we are writing a Twitter app (that’s all the rage these days, anyway). We might define a TwitterUser class like so:
class TwitterUser(val username:String) {
def url = "http://www.twitter.com/" + username
def recentTweets = // imagine some code here
}
We might write a few test cases:
val me = new TwitterUser("davetron5000")
assertEquals(10,me.recentTweets.size)
val fake = new TwitterUser("davetron5001")
assertEquals(0,fake.recentTweets)
// Along with our TwitterUser class def
object @@ { // "@" is a reserved word :(
def apply(username:String) = new TwitterUser(username)
}
// back to our test code
val me = @@("davetron5000")
val fake = @@("davetron5001")
It’s a small bit of code, and we’ve saved some typing without sacrificing readability, since we take advantage of the way Twitter refers to users via the “@” symbol.
If our app is all about Twitter, we can go a step further and just rename TwitterUser to @@ like so:
// This replaces the TwitterUser class
// and @@ singleton object
case class @@(val username:String) {
def url = "http://www.twitter.com/" + username
}
user match {
case @@("davetron5000") => "it's you, dude"
case user:@@ => "it's someone else"
}
Now, you certainly don’t want to do this for every object in your domain (you’d get a horrible mess of symbols), but for key objects that you are using everywhere, an appropriately chosen literal syntax can make your code very clean and easy to read and modify.