Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the performance impact of Scala implicit type conversions?

In Scala, is there a significant CPU or memory impact to using implicit type conversions to augment a class's functionality vs. other possible implementation choices?

For example, consider a silly String manipulation function. This implementation uses string concatenation:

object Funky {   def main(args: Array[String]) {     args foreach(arg => println("Funky " + arg))   } } 

This implementation hides the concatenation behind a member method by using an implicit type conversion:

class FunkyString(str: String) {   def funkify() = "Funky " + str }  object ImplicitFunky {   implicit def asFunkyString(str: String) = new FunkyString(str)    def main(args: Array[String]) {     args foreach(arg => println(arg.funkify()))   } } 

Both do the same thing:

scala> Funky.main(Array("Cold Medina", "Town", "Drummer"))         Funky Cold Medina Funky Town Funky Drummer  scala> ImplicitFunky.main(Array("Cold Medina", "Town", "Drummer")) Funky Cold Medina Funky Town Funky Drummer 

Is there any performance difference? A few specific considerations:

Does Scala inline the implicit calls to the asFunkyString method?

Does Scala actually create a new wrapper FunkyString object for each arg, or can it optimize away the extra object allocations?

Suppose FunkyString had 3 different methods (funkify1, funkify2, and funkify3), and the body of foreach called each one in succession:

println(arg.funkify1()) println(arg.funkify2()) println(arg.funkify3()) 

Would Scala repeat the conversion 3 times, or would it optimize away the redundant conversions and just do it once for each loop iteration?

Suppose instead that I explicitly capture the conversion in another variable, like this:

val fs = asFunkyString(arg) println(fs.funkify1()) println(fs.funkify2()) println(fs.funkify3()) 

Does that change the situation?

In practical terms, is broad usage of implicit conversions a potential performance issue, or is it typically harmless?

like image 751
Chris Nauroth Avatar asked Jun 17 '11 06:06

Chris Nauroth


People also ask

What is an implicit conversion function in Scala?

Implicit conversions in Scala are the set of methods that are apply when an object of wrong type is used. It allows the compiler to automatically convert of one type to another. Implicit conversions are applied in two conditions: First, if an expression of type A and S does not match to the expected expression type B.

What is implicit conversions?

An implicit conversion sequence is the sequence of conversions required to convert an argument in a function call to the type of the corresponding parameter in a function declaration. The compiler tries to determine an implicit conversion sequence for each argument.

What is implicit object in Scala?

In Scala, objects and values are treated mostly the same. An implicit object can be thought of as a value which is found in the process of looking up an implicit of its type.


2 Answers

I tried to setup a microbenchmark using the excellent Scala-Benchmark-Template.

It is very difficult to write a meaningful (non optimized away by the JIT) benchmark which tests just the implicit conversions, so I had to add a bit of overhead.

Here is the code:

class FunkyBench extends SimpleScalaBenchmark {   val N = 10000   def timeDirect( reps: Int ) = repeat(reps) {     var strs = List[String]()     var s = "a"     for( i <- 0 until N ) {       s += "a"       strs ::= "Funky " + s      }     strs   }   def timeImplicit( reps: Int ) = repeat(reps) {     import Funky._     var strs = List[String]()     var s = "a"     for( i <- 0 until N ) {       s += "a"       strs ::= s.funkify     }     strs   } } 

And here are the results:

[info] benchmark  ms linear runtime [info]    Direct 308 ============================= [info]  Implicit 309 ============================== 

My conclusion: in any non trivial piece of code, the impact of implicit conversions (object creation) is not measurable.

EDIT: I used scala 2.9.0 and java 1.6.0_24 (in server mode)

like image 59
paradigmatic Avatar answered Sep 18 '22 15:09

paradigmatic


JVM can optimize away the extra object allocations, if it detects that would be worthy.

This is important, because if you just inline things you end up with bigger methods, which might cause performance problems with cache or even decrease the chance of JVM applying other optimizations.

like image 31
Daniel C. Sobral Avatar answered Sep 16 '22 15:09

Daniel C. Sobral