For the Kotlin code: ``` for (i in 0 until 5) {...
# language-proposals
d
For the Kotlin code:
Copy code
for (i in 0 until 5) {
        println(i)
    }
this compiles into Java:
Copy code
for(int i = 0; i < 5; ++i) {
         System.out.println(i);
      }
However, revising it to:
Copy code
(0 until 5).forEach { i ->
        println(i)
    }
turns it into the vastly less efficient:
Copy code
Iterable $this$forEach$iv = (Iterable)RangesKt.until(0, 5);
      int $i$f$forEach = 0;
      Iterator var2 = $this$forEach$iv.iterator();

      while(var2.hasNext()) {
         int element$iv = ((IntIterator)var2).nextInt();
         int var5 = 0;
         System.out.println(element$iv);
      }
Could the compiler be optimized to recognize when it is creating an
Iterator
from a well-known
Range
, whether that's for
forEach
,
forEachIndexed
,
all
, etc., and use the more efficient for-loop instead? Adjusting the above code to use the first form instead of the second form is trivial enough, but optimizing a call like:
Copy code
(0 until 10).all { evaluatesCorrectly(it) }
ends up looking something like:
Copy code
run {
        for (i in 0 until 10) {
            if (!evaluatesCorrectly(i))
                return@run false
        }
        true
    }
which is more efficient, but not nearly as concise.
j
What does
repeat(5) { println(it) }
do by the way? (I'm AFK so I can't check). It would be more idiomatic than creating a range from 0 just to iterate on it.
That doesn't work for
all
, though
e
the compiler doesn't specialize inline functions for different types - all uses of the same function use the same(-ish) bytecode
an explicitly specialized overload IntRange.forEach would get you the result you want though
d
repeat
uses for-loops as one would expect, but I'm using
0 until 5
as a placeholder example here.
e
there is some idea to optimize the bytecode after inlining but it hasn't been done https://youtrack.jetbrains.com/issue/KT-18802
d
That proposal matches exactly what I'm looking for, thanks. There's a mention at the end of, "decided to provide an optimization of inlined
for
-loops at bytecode postprocessing stage," is that particular decision tracked anywhere or is it completely in limbo?
e
not anywhere else I've seen
m
Are you sure it's less efficient after JITC
d
Testing these methods with Java Microbenchmark Harness:
Copy code
fun rangeWithForLoop(blackhole: Blackhole) {
    for (i in 0 until 1_000_000) {
        blackhole.consume(i)
    }
}

fun rangeWithForEach(blackhole: Blackhole) {
    (0 until 1_000_000).forEach {
        blackhole.consume(it)
    }
}
I got these results:
Copy code
Benchmark                    Mode  Cnt  Score   Error  Units
RangeBenchmark.rangeForEach  avgt   20  1.306 ± 0.026  ms/op
RangeBenchmark.rangeForLoop  avgt   20  1.017 ± 0.083  ms/op
so it is less efficient even after JITC.