0

Disclaimer: I came to Scala from C#, where I really appreciated LINQ. Therefore, I immediately felt at home with iterators and sequences. I missed yield "C# style", but I was able to cook my own with continuations... even if it pays a performance penalty.

Now, when I miss some method over collections in C#, I just define it as an extension method, and the compiler does a very nice job of treating code efficiently. In Scala, I use the Pimp enrich My Library approach, but I am a little bit worried about performances.

Contrary to my "yield iterator", however, this is a recognized and common patter. Does the Scala compiler optimize it, removing the creation of the temporary object?

class RichFoo(f: Foo) {
  def baz = f.bar()
  def baz2 = f.bar() * 2
}
object RichFoo {
  implicit def foo2Rich(f: Foo) = new RichFoo(f)
}

// on the caller side
val f : Foo = ....
f.baz
f.baz2
// this translates, literally, to new RichFoo(f).baz, new RichFoo(f).baz2

If not, why? It looks like a good and safe optimization to me. Can I "hint" or "force" the compiler in the right direction? Which faster alternatives are there?

I would like to use the pattern for my collection of algorithms over iterators/iterable, so I can write them as filter/map/etc collection.baz(lambda).bar(lambda2) but I am afraid it will prove to be too "heavy". (Compared to the more efficient/direct, but ugly bar(lambda2, baz(lambda, collection))

0__
  • 66,707
  • 21
  • 171
  • 266
Lorenzo Dematté
  • 7,638
  • 3
  • 37
  • 77
  • 1
    The fastest alternative to the date is to use **implicit value classes** (available in 2.10) so compiler will try as hard as it can to elide those *rich* wrapper classes and to inline methods you've introduced. – om-nom-nom Mar 07 '13 at 13:58
  • @om-nom-nom sounds good... are there any posts/papers/... where can I read how is it done and which are the performance benefits? Also, what can I do if I'm stuck with 2.9.1? – Lorenzo Dematté Mar 07 '13 at 14:00
  • 3
    Aside from pretty good spec on [value classes](http://docs.scala-lang.org/sips/pending/value-classes.html) and [implicit classes](http://docs.scala-lang.org/sips/pending/implicit-classes.html) you may [start with this post](http://java.dzone.com/articles/scala-210-%E2%80%93-or-why-you-will). Sadly looks like unlike [another proposal](http://docs.scala-lang.org/sips/pending/futures-promises.html) those two features won't be backported to 2.9.4 (which is binary compatible with 2.9.1 and planned to come out in august). – om-nom-nom Mar 07 '13 at 14:05
  • @om-nom-nom thank you, the spec on value classes is what I was looking for. Am I right that this optimization will also work for native types? I'm thinking of Int here (without boxing?), or Array[T]? – Lorenzo Dematté Mar 07 '13 at 14:09
  • As @RégisJean-Gilles pointed to me some time ago, although this feature named *value* classes, it should work with both primitive and reference types underneath, so looks like pimping Array[T] should be fine. – om-nom-nom Mar 07 '13 at 14:12
  • The standard name for this pattern is now **enrich** my library. Which, aside from the possibly offensive former reference, also more closely matches the naming used in code (i.e. RichX). – Rex Kerr Mar 07 '13 at 15:07

1 Answers1

3

As @om-nom-nom comments, the solution here (in 2.10) is to use an implicit value class.

implicit class RichFoo(val f : Foo) extends AnyVal {
  def baz = f.bar()
  def bax = f.bar()
}

RichFoo exists now at compile time, but at runtime this is optimized into a static method call, and so should impose no performance penalty.

See Value classes (SIP)

See also Mark Harrah's Introduction to Value Classes which gives a good overview from the usage perspective.

Impredicative
  • 5,039
  • 1
  • 17
  • 43