18

If I want to add a method to a class in Scala, I need to do something like:

class RichFoo(f: Foo) {
  def newMethod = f.bar()
}
object RichFoo {
  implicit def foo2Rich(f: Foo) = new RichFoo(f)
}

Then f.newMethod will result in creation of RichFoo instance and call its method.

I'm trying to understand why it was not defined similarly to Ruby:

override class Foo {
  def newMethod = bar
}

The compiler can look at this definition, and create a FooOverride class with static method newMethod that gets a parameter of type Foo and calls its bar method. This is how Scala implements traits. I still need to import the package containing the Foo override to use it.

It seems to involve less typing, doesn't require me to invent names, and has better performance (not calling a method and creating an object). Anything the implicit conversion method does can be done inside the additional method.

I'm sure I've missed something and would like to get an insight into what.

matanster
  • 15,072
  • 19
  • 88
  • 167
IttayD
  • 28,271
  • 28
  • 124
  • 178
  • Does Ruby really out perform Scala in this case, or are you speculating that an open class implementation can be made as fast as a closed on? – Pete Kirkham Dec 16 '09 at 21:47
  • 3
    I suggest a facade that looks like you're reopening a class, but in fact just calls static methods. The scala compiler does such things all the time (traits are compiled into an interface and a class with static methods). I speculate that it is less coding and faster compared to the current implicit defs way – IttayD Dec 17 '09 at 09:34

2 Answers2

13

There are other uses for implicit conversions other than just the "pimp my library" idiom, so it's not really a case of "why didn't they do this instead?", but "why didn't they do this as well?". Certainly, I can see no reason why an extension methods syntax couldn't be added as you suggest, and it would probably be somewhat cleaner, but there's not much pressing need for it given that the language already supports a way of achieving the same effect.

Update October 2011:

There's a new proposal to add syntax sugar for this use case: http://scala.github.com/sips/pending/implicit-classes.html

Matt R
  • 9,892
  • 10
  • 50
  • 83
  • 1
    Your answer is correct. I wanted to point out that in fact, there is an experimental extension to the Scala compiler (called Scala-virtualized) which supports adding methods to existing classes by writing less code - look for "def infix_+" in this class to find some examples: https://github.com/TiarkRompf/virtualization-lms-core/blob/e11ee5c5c9eb5d00e38927f5f1722bc956e8615d/src/ppl/StringOps.scala Scala-virtualized supports also other features, for which the best reference (though incomplete) is this: https://github.com/tiarkrompf/scala-virtualized/wiki – Blaisorblade Oct 18 '11 at 12:54
8

How do you prevent that method from entering scope without requiring explicit importing and giving it a name? In fact, how can a program know what methods were added without doing so?

When you use three different libraries, two of which add methods to the third in an incompatible way, how would you get around that without having implicits under control?

Aside from that, better performance is not possible, as JVM doesn't allow one to change an existing class. At best, you could gain the benefit of not having to invent a name and having to type less at the cost of not being able to control what is being done.

As a final note, if you want short, you can do:

implicit def fooBar(f: Foo) = new { def newMethod = bar }
Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
  • 2
    I import Foo's override instead. I didn't suggest changing the class. I suggested that foo.bar will be converted to com.my.package.Foo.bar(foo). Your last example means calling newMethod through reflection – IttayD Dec 16 '09 at 11:33
  • 4
    The `new { ... }` thing is a structural type. Be careful with this: its methods are called via reflection, which makes it slow. See http://stackoverflow.com/questions/3119580/scala-equivalent-of-csharps-extension-methods/3119671#3119671 – Jesper Jan 29 '11 at 10:19