Sunday, September 4, 2011

Method receiver implicit conversions - data units use case

Scala implicit conversion is a great concept, basically you can use this feature to simplify object instanciation, I mean avoiding java constructor profusion by just providing in scala one construtor, and a set of implicit conversions (and of course default values). What's great with implicits is that they also apply on the receiver, let's see an example.

We want to be able to give durations or bytes size in a natural way, let's start a scala console through the sbt console, and try out my "unittools" library (download link : unittools.tar.gz) :
dcr@lanfeust ~/dev/unittools $ sbt
[info] Set current project to default-0b115b (in build file:/home/dcr/dev/unittools/)
> console
[info] Starting scala interpreter...
Welcome to Scala version (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_26).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import unittools.UnitTools._
import unittools.UnitTools._

scala> "10h50m30s".toDuration
res0: Long = 39030000

scala> "1gb100kb".toSize
res1: Long = 1073844224

scala> 15444002.toDurationDesc
res1: String = 4h17m24s2ms

scala> 68675454743L.toSizeDesc
res2: String = 63gb982mb17kb791b

That's quite better to write "10h50m30s" inside your configuration files instead of "39030000", or "4h17m24s2ms" instead of "15444002" if you have to report a response time !

Of course strings don't have toDuration and toSize methods, in fact the "import unittools.UnitTools._" makes new implicit conversion definitions available to the compiler, those conversions make possible to convert a String instance to an internal object instance for which toDuration or toSize is available.

the "plumbing" is the following :
package unittools

class DurationHelper(value:Long, desc:String) {
  def toDuration()=value
  def toDurationDesc()=desc

class SizeHelper(value:Long, desc:String) {
  def toSize()=value
  def toSizeDesc()=desc

object UnitTools {
  // Implicit conversions
  implicit def string2DurationHelper(desc:String) = new DurationHelper(desc2Duration(desc), desc)
  implicit def long2DurationHelper(value:Long) = new DurationHelper(value, duration2Desc(value))

  implicit def string2SizeHelper(desc:String) = new SizeHelper(desc2Size(desc), desc)
  implicit def long2SizeHelper(value:Long) = new SizeHelper(value, size2Desc(value))


it's worth noting that the scala unittool internal algorithm contains less code than the java release I first made; 25 lines for scala, 40 lines for java.

CONTEXT : Linux Gentoo / Scala 2.9.1 / Java 1.6.0_26 / SBT 0.10 / ScalaTest 1.6.1

No comments:

Post a Comment