Monkey Patching in Scala

Created On:

A really cool feature of Scala’s type system is implicit conversions. It is a type safe way of adding methods to a class without the flaws of global monkey patching.

For example in Ruby it is very easy to add methods to a class because in Ruby all classes are open. For example I can add any method to Fixnum by doing the following anywhere in my code:

class Fixnum
  def positive?
    self > 0
  end
end

Then anywhere else in my code I can have the following evaluate to true:

x = 10
x.positive?

The biggest drawback from doing this in Ruby is monkey patches are in the global scope. If you use any class that relies on any monkey patching then that monkey patching is also in your scope. At best it won’t effect any of your code, at worst it can silently override methods in your code. This can lead to horrible problems that will cause you to cry.

Scala however lets you accomplish the same thing without polluting the global scope. It achieves this by the use of implicits, a mechanism to instruct the compiler to transparently convert one type to another at compile time.

The way it works is as follows:

object Main {
  implicit class FancyInt(val x: Int) extends AnyVal {
    def positive_? = x > 0
  }

  def main(args: Array[String]) {
    println(3.positive_?)
  }
}

The implicit class instructs the compiler that any Int can be implicitly converted to a FancyInt and that FancyInt has a positive_? method. This allows us to invoke the positive_? method on any Int and the compiler will know what we want. Unlike Ruby however this is only visible to the scope that the implicit is visible in. This allows us to build Ruby like DSLs without the fuss of global monkey patching.


Note: Disqus has been removed from this blog, but below is a copy of some of the comments on this post for posterity.


Jiri Pospisil

Note that you can get the same behavior with Ruby's new "refinements" feature.

Charles Feduke

C# achieves similar functionality using extension methods. I prefer the Scala approach as I've used it to good effect in my code. In Ruby its important to note that you can replace behavior in a pinch through monkey patching - which, yes, can lead to great sadness. (I have never tried overriding behavior using an implicit conversion in Scala, I suppose it would work since the compiler implicitly converts the original type at compile time.)

AGhost_7

Implicit classes aren't implicit conversions. You can make implicit conversions using implicit def, but that's a different story. Consider the following code:

class Foo { def bar = println("foo") }
implicit class bazOverload(val self: Foo) { def bar = println("baz") }
val foo = new Foo
foo.bar
> foo

Overrides don't work (but this will still compile), and that's because the compiler will only look for the implicit class if the current class doesn't have the method you're trying to call.

Juan Vazquez

Groovy does this with categories. http://mrhaki.blogspot.com/...

BeepDog

Thanks for this! It really helped me grasp implicits, especially around the Spray.io JSON stuff, and why things blew up if I didn't have them in a certain order.

Muhammad Hewedy

* Objective-c also support Monkey patches, they call it Categories.
Once you #import the Category in your class, you can use the new methods.

* This also a inherent feature of prototype-bases OOP, and this exists in Javascript as an exmple.

Julien Diener

There is monkey patching in python as well, it's actually even simpler because classes are just some traditional objects (i.e. instance of the class type), and in python everything is writable. So

[module1.py]
class A(object):
def f(self): print "A"

[module2.py]
def f(self): print "B"
A.f = f

if only module1 is imported, A().f() will print "A", but as soon as module2 is imported (anywhere), any instance of A would print "B", even existing ones that are used elsewhere. It can be very practical (to patch external lib for example) but quite dangerous too. As pythonistas say "we are all adults here".