3

Here's an example of a snippet of code that, at first impression, looks like something that scalac could easily optimize away:

val t0 = System.nanoTime()
for (i <- 0 to 1000000000) {}
val t1 = System.nanoTime()
var i = 0
while (i < 1000000000) i += 1
val t2 = System.nanoTime()

println((t1 - t0).toDouble / (t2 - t1).toDouble)

The above code prints 76.30068413477652, and the ratio seems to get worse as the number of iterations is increased.

Is there a particular reason scalac chooses to not optimize for (i <- L to/until H) into whatever bytecode form javac generates for for (int i = L; i < H; i += 1)? Might it be because Scala chooses to keep stuff simple and expect the developer to simply resort to the more performant forms such as a while loop when raw looping speed is required? If yes, why is that good, given the frequency of such simple for loops?

Erik Kaplun
  • 37,128
  • 15
  • 99
  • 111
  • Because it not that easy. The compiler would have to know how the implementation of the `foreach` looks like on the object you are passing in. There are many things that can go wrong with such optimizations. – drexin Sep 23 '13 at 13:12
  • Definitely, but it could special case ` to/until ` at least—isn't such information statically available at compile time with sufficient reliability? – Erik Kaplun Sep 23 '13 at 13:13
  • 1
    Check out [Spire](https://github.com/non/spire)'s `cfor` and [`cforRange`](https://github.com/non/spire/commit/6dc6559e7e0814f54745a7427fd5fe216076af10), which provide exactly this kind of optimization via macros. – Travis Brown Sep 23 '13 at 13:19
  • Aha, I was actually wondering already if macros could be used to work around this :) Although I do wish the `cfor` macros could simply optimize existing `for (...)` constructs, something which I'm sure Lisp macros could do. – Erik Kaplun Sep 23 '13 at 13:20
  • 3
    See also [Scalaxy](https://github.com/ochafik/Scalaxy). I haven't had a chance to try it out lately, but there's some neat stuff in there. – Travis Brown Sep 23 '13 at 13:22
  • @ErikAllik: jvm can inline `foreach` method. after inlining you'll get `while` loop. This optimization works not only for ranges. Scalac should not know about `Range` class - it's not a part of the language itself. As already noted, in extremely rare cases when you do need such optimizations at compile time you could use third-party libraries, such as `Scalaxy`. – senia Sep 23 '13 at 13:57

1 Answers1

3

for-comprehensions performance in Scala is a very long running debate right now.

See the following links:

TL,DR: the Scala team decided to concentrate on more general optimizations than the ones that would have to favour some particular classes and edge-cases (in this case: Range).

Piotr Kołaczkowski
  • 2,601
  • 12
  • 14
  • So are the more general optimizations going to ever somehow generically handle the `Range` case as well? Even in theory? – Erik Kaplun Sep 23 '13 at 14:07
  • @ErikAllik: [`@inline` annotation](http://www.scala-lang.org/api/current/#scala.inline) on [`foreach` method](https://github.com/scala/scala/blob/v2.10.2/src/library/scala/collection/immutable/Range.scala#L135). – senia Sep 23 '13 at 14:19