Sunday, 22 February 2009

Scala, implicit conversions

Today, a small posting on the implicit conversion feature of Scala.

Implicit conversions provide a powerful way to extend classes with new functionality, as if already built into the library or even the language itself. There are similarities with C# extension methods, but Scala's implicit conversion mechanism is more concise, flexible and maintainable.

To define an implicit conversion in Scala, the syntax is:

impict def myImplicitConversionName(n: type) = new MyConversionType(n)

The scenario is that you want to add some new method(s) or functionality to instances of an existing class for which may be final/sealed or where sub-classing is inappropriate or not possible / effective. Implicit conversions provide a very natural way to add functionality and to users it will appear as natural features of the language/library, no special syntax is required.

A good example is provided on the Scala site: http://www.scala-lang.org/node/226

Which is a good example because it shows exactly the reasons why you might want to extend the language or library. In this case, the type int provides a good candidate for extension - to add the ! factorial function as if it was natural function of the type int.

I wanted to expand on this example by providing a couple of examples of the same thing with further explanation.

Example 1: explicitly defining a class that provides the extensions and using it in the implicit def


object extendBuiltins2 {

// the important bit, it says there's an implicit conversion from int to Factorizer(n : int)
implicit def int2fact(n: Int) = new Factorizer(n)

def main(args : Array[String]) = {

// when the compiler sees this, it will first 'look for' ! method in int,
// when it doesn't find it, it will look for an implicit conversion on int that provides !
// which is of course exactly what we've just provided in the Factorizer class
println("10! = " + (10!))
}

// define ! as a method on a class that can be constructed from int - this class will
// provide the implicit conversion that supplied an implementation of ! on int
class Factorizer(n: Int) {

def ! = fact(n)
}

// the plain old factorial function
def fact(n: Int): BigInt =
if (n == 0) 1 else fact(n-1) * n
}


The key line that defines the implicit conversion is this:

implicit def int2fact(n: Int) = new Factorizer(n)

what we are saying is that there is an implicit conversion from type int to type Factorizer(int) - so where we have an int, if ! is called the compiler will look for ! on int and fail to find it. It will then seek an implicit conversion that can convert from int in order to provide this method ! - where it finds our implicit conversion definition that uses the Factorizer class to provide the implementation of !

One reason this is more powerful than extension methods is that a whole class of functionality can be added to an existing class without explicitly extending all the methods individually. This has important benefits when it comes to maintenance, if the definition of the extending class changes, you get those changes automatically, you do not have to modify all the extension methods to match.


Example 2: equivalent to the above example but using an anonymous class for a more concise solution where the explicit definition of a class is of no other use.


/* More concise way of adding ! as a method on int's - no explicit class definition */
object extendBuiltins {

implicit def int2fact(n: Int) = new {

def fact(n: Int): BigInt =
if (n == 0) 1 else fact(n-1) * n

def ! = fact(n);
}

def main(args : Array[String]) = {

println("10! = " + (10!))
}
}


This achieves the same this as example 1 but does so more concisely with the anonymous class, constructed using the convenient = new {} syntax.


.

1 comment:

piboi said...

Woah, didn't know about this anonymous class syntax. Scala just got even more awesome!