Pragmatic Programmer Issues

Scala Implicit Conversion

I’ve just finished Programming in Scala by Martin Odersky. So in next few post I will describe my thoughts about Scala. Shortly I recommend you to get know something about this language. I quote:

"If I were to pick a language to use today other than Java, it would be Scala" by James Gosling

"I can honestly say if someone had shown me the Programming in Scala book by by Martin Odersky, Lex Spoon & Bill Venners back in 2003 I’d probably have never created Groovy." by James Strachan.

Interesting, isn’t it?

Scala has a lot of futures we do not have in java, one thing I like about scala is that most of new features  are de facto libraries, this libraries simply extend language (the name scala comes from scalable language). 

In this post I will focus on implicit conversions. It is similar to java cast, which are explicit, but of course implicit conversion are more powerful feature, which is used in scala to extend existing libraries easier.

Implicit conversion is a function which takes one type as parameter and return other type. Example in java space will be String.valueOf(int i) which takes int type and return String object. So where is the fun in this 🙂

The fun comes from fact that this functions are applied implicitly by compiler with full type check. To do this compiler require to follow some rules:

  1. Implicit conversion must be in scope as single identifier, or be associated with the source or target type.

    /* put conversion into scope */
    import Preamble._  /* many libraries import in this way library implicit conversions"
    /* or  as companion object */
    class Person { ... }
    object Person {
    /* implicit conversions goes here for Person type */
    }
    
  2. One conversion at the time, so there isn’t implicit conversion chaining.
  3. There may be only one way to apply implicit conversion, otherwise compiler rise error.
  4. And the last is of course that explicit has priority.

Writing implicit conversion is very easy, we just put implicit keyword before method, and we are done. The name of the implicit conversion depends on developer, I mostly saw type2target convention as example some implicit conversion from Predef: any2ArrowAssoc, int2double etc. Of course there are also typeToTarget and typeWrapper as well.
Want to assign double to int just wirte this implicit and it works.

scala>  implicit def double2int(d:Double): Int = d.toInt
scala> val i : Int = 3.5

Ok so what we can do with implicit conversions. Implicit conversion is tried in such situations:

  1. As expected type (extended cast alike).
  2. Receiver conversion.
  3. Also as implicit parameters

First rule applies in many cases, as behind the scene action. For example assume this code:

val d : Double = 3 /* 3 is Integer */
/* this code is translated by compiler into val d: Double - Predef.int2double(3) */

It works perfectly because in fact compiler is using Predef.int2double implicit conversion. We can do in such way proper object translation to use it with current libraries.

Map( "first"->"Test", "second"->"Code")

It looks like a special syntax but in fact it is just implicit conversion in action. The code is translated into:

  Map.apply(any2ArrowAssoc("first").->("Test"), any2ArrowAssoc("second").->("Code"))

I omit generics and Predef package to make this code more readable, as we see this "syntax" in fact use any2ArrowAssoc implicit conversion defined in Predef.

As all we know with great power, comes great responsibility. It may be hard to know what is going on with my code, when implicit conversions are overused. So key fact is that always we can use implicit conversion as normal method and call it explicit. Second scala compiler has -Xprint:typer option parameter which can be use to show scala code after applying implicit conversions. I was using it to show the code of Map pseudo-syntax. Example looks like this:

/* scala code Test.scala */
object Test extends Application {
  Map( "first"->"Test", "second"->"Code")
}

Console output

pedro$ scalac -Xprint:typer Test.scala 
[[syntax trees at end of typer]]// Scala source: Test.scala
package  {
  final object Test extends java.lang.Object with Application with ScalaObject {
    def this(): object Test = {
      Test.super.this();
      ()
    };
    scala.this.Predef.Map.apply[java.lang.String, java.lang.String](
scala.this.Predef.any2ArrowAssoc[java.lang.String]("first").->[java.lang.String]("Test"), 
scala.this.Predef.any2ArrowAssoc[java.lang.String]("second").->[java.lang.String]("Code"))
  }
}

There are also implicit parameter which also use implict to add additional parameter to the method calls. Implicit conversion is quite simple but very powerful feature, isn’t it? What do you think about it? In my opinion is quite useful.

Categories