Update: This article was written for Scala 2.9. Things changed a little bit in Scala 2.10, so see this new article, Creating implicit methods in Scala 2.10, for correct examples for 2.10 and newer versions of Scala.
A cool thing about implicit conversions in Scala is that they let you add new methods to existing classes, including existing Java and Scala classes such as String, File, and so on.
For instance, let's say you want to add a method to the Java String class, and this new method will increment each character in the String by one byte. The first thing you do is define a Scala class that has a method that implements the behavior you want:
class BetterString(val s: String) {
def increment = s.map(c => (c + 1).toChar)
}
In that class I created a new method named increment, which uses the String the class is created with, and returns a new String, where each character in the String has been increased by one byte ('A' becomes 'B', 'B' becomes "C', and so on).
Next, I define an implicit conversion that ties my new class to the existing Java String class:
implicit def stringToString(s: String) = new BetterString(s)
Notice that the stringToString method is a very normal looking Scala function, but because it's preceded by the implicit keyword, some very cool "magic" happens. Here's how this works:
As a result, I've tied my increment method to the String class, so I can now type something like this:
"foo".increment
If you're new to implicit conversions, I'm sure that's still a little hard to understand, so let's take a look at how this works in the Scala REPL. First we define our class:
scala> class BetterString(val s: String) {
| def increment = s.map(c => (c + 1).toChar)
| }
defined class BetterString
That looks just like a normal Scala class, no magic there. Next we define our stringToString function:
scala> implicit def stringToString(s: String) = new BetterString(s) stringToString: (s: String)BetterString
Again, except for the implicit keyword, that looks like a normal function.
And now it's time for the big test. Let's create a String literal and then see if our increment method will work:
scala> "HAL".increment res0: String = IBM
As you can see from that last line, I typed in the String "HAL", then followed it with my increment method, and that method returned a new String "IBM", which is the result of incrementing each character by one byte.
To help you understand what's happening here, I encourage you to add more methods to my Scala class and see if you can make them work. For instance, try implementing a "backwards" method, and see if you can make that accept a String, and print the String in reverse order. (Note that there's already a String method named reverse, and you can use that in your "backwards" method.
As another test, try to implement a method that has the same name as an existing String method. For instance, try to define and then use a method named reverse and see what happens.
As you've seen, you can extend existing classes in Scala using implicit conversions. To implement this recipe of adding new functionality to existing classes, you:
Two more notes before I go:
I hope this example of how add new methods to existing classes in Scala has been helpful.
Post new comment