Avoid structural types when pimping libraries

I came across this answer to a StackOverflow question by Mitch Blevins, about using the “Pimp My Library” pattern. Most Scala programmers will sooner or later discover this pattern. I’ve used it myself in my Scala ray tracer. I have a class Vector that represents a vector in 3D space. One of the methods it contains is a method to scale a vector uniformly with a factor:

final class Vector (val x: Double, val y: Double, val z: Double) {
	// ...
	
	// Scale a vector
	def *(f: Double) = new Vector(x * f, y * f, z * f)
}

So now I can write:

val a = new Vector(1.0, -1.0, 2.0)
val b = a * 1.5

// But I also want to be able to write this:
val c = 1.5 * a

Ofcourse, the Double type doesn’t have a * method that takes my class Vector as an argument. To make it work, I wrote an implicit method:

// Implicit conversion for scaling vectors by multiplying a numeric type with a vector
implicit def implicitScaleVector[N <% Double](f: N) = new {
	def *(v: Vector) = v * f
}

Note that the implicit method returns an “anonymous object” that contains the actual * method, which calls the * method defined in class Vector to do the work.

Ok, good, that works. But there’s an interesting problem with this implementation that Daniel Spiewak points out in a comment to Mitch’s answer: he says that the new { ... } syntax causes the compiler to infer a structural type, so that the * method inside the “anonymous object” will be called via reflection – which is much slower than a regular method call.

I wanted to see that for myself, so I wrote a small test program. Let’s first see how long the * method in class Vector takes to run:

class Vector (val x: Double, val y: Double, val z: Double) {
	def *(f: Double) = new Vector(x * f, y * f, z * f)
}

object Test {
	def time(block: => Unit) = {
		val start = java.lang.System.nanoTime()
		block
		val time = java.lang.System.nanoTime() - start
		println("time: " + time / 1e6 + " ms")
	}

	def main(args: Array[String]) {
		time {
			var v = new Vector(1.0, -1.0, 2.0)
			for (i <- 0 to 1000000) v = v * 1.5
		}
	}
}

I ran this a few times, it takes approximately 130 ms on my system. Now let's try the original version with the new { ... } syntax:

object Test {
	implicit def implicitScaleVector(f: Double) = new {
		def *(v: Vector) = v * f
	}

	// ...
	
	def main(args: Array[String]) {
		time {
			var v = new Vector(1.0, -1.0, 2.0)
			for (i <- 0 to 1000000) v = 1.5 * v
		}
	}
}

That is indeed a lot slower, on my system this takes about 280 ms, more than twice as slow! This performance problem can be solved by avoiding using a structural type:

object Test {
	class Result (f: Double) {
		def *(v: Vector) = v * f
	}

	implicit def implicitScaleVector(f: Double) = new Result(f)

	// ...
}

This indeed performs much better, it takes only about 140 ms - almost as fast as calling the * in class Vector directly.

There is one thing I don't like about this however, and that's that I need an additional class that's polluting the namespace. I tried to fix this by declaring the class inside the method:

object Test {
	implicit def implicitScaleVector(f: Double) = {
		class Result (f: Double) {
			def *(v: Vector) = v * f
		}

		new Result(f)
	}

	// ...
}

Unfortunately that doesn't work! This is just as slow (280 ms) as the original version with the new { ... } syntax. That's because class Result is now not known to the caller of the implicit method, so that it still needs to infer the structural type and call the method via reflection.

This is an interesting gotcha to be aware of when pimping libraries or using structural types in other ways.