Vladimir Vainer
01/13/2023, 1:42 AMephemient
01/13/2023, 1:56 AMarray.map { it * 2 }.sum()
will perform worse than
array.sumOf { it * 2 }
will perform like
var sum = 0
for (int in array) sum += int * 2
ephemient
01/13/2023, 1:58 AMVladimir Vainer
01/13/2023, 4:51 AMJoffrey
01/13/2023, 9:18 AMsumOf
perform worse than the for..in
loop? I thought it was inlined to do exactly the same thing. Doesn't for..in
use iterators behind the scenes? If yes, I guess the "fastest" would be to avoid iterators completely by using a for loop on indices and directly accessing the primitives in the array, right? But maybe the compiler optimizes the iterator away, in which case I understandephemient
01/13/2023, 9:32 AMsumOf
as being generic, but it actually has distinct overloads for different primitive output typesKlitos Kyriacou
01/13/2023, 10:01 AMBut maybe the compiler optimizes the iterator away, in which case I understand (edited)Indeed, it does. From https://kotlinlang.org/docs/control-flow.html#for-loops:
Aloop over a range or an array is compiled to an index-based loop that does not create an iterator object.for
ephemient
01/13/2023, 10:20 AMfor
over a List
compiles to an iterator-based loop, but for common list implementations, iterating over indices and using get
performs betterephemient
01/13/2023, 10:20 AMephemient
01/13/2023, 10:21 AMfor (item in list) { ... }
though, and not for (index in list.indices) { val item = list[index]; ... }
, because the readability matters moreJoffrey
01/13/2023, 10:35 AMfor over a List compiles to an iterator-based loop, but for common list implementations, iterating over indices and using get performs betterYeah that's exactly why I was asking this for the case of arrays, because I've been bitten by this for lists once.
Joffrey
01/13/2023, 10:37 AMreadability matters moreYeah I actually almost never use loops at all, because usually extension functions express the intent better. But if I really have to, I'll use the
for in
with iterator despite the perf issue, it's so much more readable. I think the profiler only highlighted the perf problem once for me, for a specific use case of Minecraft, processing tons of 3D blocks. In other cases it was always something elseKlitos Kyriacou
01/13/2023, 10:55 AMList
that gets initialized at the start and then never gets modified again, you should just create an array from that list (by calling toArray()
) and use the array from then on.
This is because the overhead, with both iterator and indexed access, is due to extra checks. Iterator access checks for co-modifications (which are unnecessary if there are no modifications), and Java's ArrayList.get()
checks for out-of-bounds access, even though it doesn't need to because array indexing also does this check (I presume ArrayList does an additional check so that the exception message doesn't mention internal implementation details).Joffrey
01/13/2023, 10:58 AM