I'm a software developer with over 20 years development experience (10 years with Smalltalk, more than 10 years with Java) working mostly on client/server applications for banks, planning systems or manufacturing systems. My favorite areas in computer science are concurrent and/or distributed systems. I like to have a look at things such as Scala, JavaSpaces, Hadoop, actors, STM, and things alike. Oliver has posted 3 posts at DZone. You can read more from them at their website. View Full User Profile

Implicits in Scala: Conversion on Steroids

09.07.2013
| 3570 views |
  • submit to reddit

With the use of implicits in Scala you can define custom conversions that are applied implicitly by the Scala compiler. Other languages provide support for conversion, e.g. C++ provides the conversion operator (). Implicits in Scala go beyond what the C++ conversion operator makes possible. At least I don't know of any other language where implicit conversion goes that far as in Scala. Let's have a look at some sample Scala code to demonstrate this:

 	class Foo { 
    def foo {
        print("foo")
    }
}

class Bar {
    def bar {
        print("bar")
    }
}

object Test
{
    implicit def fooToBarConverter(foo: Foo) = {
        print("before ")
        foo.foo
        print(" after ")
        new Bar
    }       
    
    def main(args: Array[String]) {
        val foo = new Foo
        foo.bar 
    }
}

Running Test.main will print "before foo after bar" to the console. What is happening here? When Test.main is run the method bar is invoked on foo, which is an instance of class Foo. However, there is no such method bar defined in class Foo (and in no superclass). So the compiler looks for any implicit conversion where Foo is converted to some other type. 

It finds the implicit fooToBarConverter and applies it. Then it tries again to invoke bar, but this time on an instance of class Bar. As class Bar defines some method named bar the problem is resolved and compilation continues. 

For a more detailed description about implicits compilation rules see this article by Martin Odersky, Lex Spoon, and Bill Venners. Note that no part of the conversion code from Foo to Bar is defined either in class Foo nor in class Bar. This is what makes Scala implicits so powerful in the given sample (and also a bit dangerous as we shall see in the following example).

If we tried to get something similar accomplished in C++ we would end up with something like this (C++ code courtesy to Paavo Helde, some helpful soul on comp.lang.c++):

#include <iostream>

class Foo {
public:
    void foo() {
        std::cout << "foo\n";
    }
};

class Bar {
public:
        Bar(Foo foo) {
                std::cout << "before\n";
                foo.foo();
                std::cout << "after\n";
        }
    void bar() {
        std::cout << "bar\n";
    }
};

void bar(Bar bar) {
    bar.bar();
}

int main() {
      Foo foo;
      bar(foo);
} 

There are also "to" conversion operators defined by the syntax like:

 	class Foo {
            operator Bar() const {return Bar(...);}
};

Note that such conversions are often considered "too automatic" for robust C++ code, and thus commonly the "operator Bar()" style conversion operators are just avoided and the single-argument constructors like Bar(Foo foo) are marked with the 'explicit' keyword so the code must explicitly mention Bar in its invocation, e.g. bar(Bar(foo)).

The C++ code including the comment in the paragraph above is courtesy to Paavo Helde. As it can be seen it is not possible in C++ to achieve the same result as with implicits in Scala: There is no way to move the conversion code completely out of both class Foo and Bar and getting things to compile. So conversion in C++ is less powerful than in Scala on one hand. On the other hand it is also less scary than implicits in Scala where it might get difficult to maintain a large Scala code base over time if implicits are not handled with care.

Looking for a matching implicit to resolve some compilation error can keep the compiler busy if it repeatedly has to look through a large code base. This is also why the compiler only tries the first matching implicit conversion it can find and aborts compilation if applying the found implicit won't resolve the issue. Also, if implicits are overused you can run into a situation where you need to step through your code with the debugger to figure out the conversion that results in a different output being created than expected. This is an issue that made the guys developing Kotlin drop implicits from their Scala-like language (see reference). The problem that you can shoot yourself into your foot when overusing implicits is well known in the Scala community, for instance in "Programming in Scala" [1] it says on page 189: "Implicits can be perilously close to "magic". When used excessively, they obfuscate the code's behavior. (...) In general, implicits can cause mysterious behavior that is hard to debug! (...) Use implicits sparingly and cautiously.".

What remains on the positive side is a powerful language feature that has often proven to be very useful if applied with care. For instance Scala implicits do a great job in glueing together disparate APIs transparently or in achieving genericity. This article only dealt with one specific aspect of implicits. Scala implicits have many other applications, see f.ex. this article by Martin Odersky, Lex Spoon, and Bill Venners.

[1] "Programming Scala", Dean Wampler & Alex Payne, O'Reilly, September 2009, 1st Edition.

Published at DZone with permission of its author, Oliver Plohmann.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Jochen Bedersdorfer replied on Sat, 2013/09/07 - 2:11pm

 I've yet to see one good example of having implicit conversions.

It's too much magic and doesn't make the life easier of the person having to read the code.

Scala seems to need a book that highlights which features NOT to use, really.
And then good luck in enforcing those guidelines in a bigger organization.

Silvio Bierman replied on Sat, 2013/09/07 - 6:19pm in response to: Jochen Bedersdorfer

Implicit conversions are used by the standard library, largely to allow arrays and primitives to be used in a more high-level way and integrate better with the higher level collections and types.

I do not think they are very useful in plain application code but they can aid a library designer to allow user code to be simpler and more expressive.

Enforcing language usage guidelines in bigger organizations is always difficult. For any language. To disallow using specific features (or libraries) is in the easiest to enforce category.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.