Your microbenchmark simply finds that whichever of the two approaches you run first is slower than the one you run second. If I run your code, I can reproduce count()
coming out an order magnitude slower than size
... but if I reverse the order of the tests and try testing size
first, then suddenly size
is an order of magnitude slower than count()
. Such is the danger of this kind of naive microbenchmarking.
As Adam Millerchip notes, in cases where the compiler is smart enough to notice that an object you call count()
on is a Collection
, the call should get inlined to size
and so (I think?) compile down to completely identical bytecode, thanks to this implementation of Collection<T>.count()
in the Kotlin standard library:
@kotlin.internal.InlineOnly
public inline fun <T> Collection<T>.count(): Int {
return size
}
Certainly there's no way count()
should ever come out faster than size
, since count()
just defers to size
under the hood. At worst, the Iterable<T>.count()
method will run, which checks if this
is a Collection
and defers to its size
method if so (and thus must be slower since it's doing strictly more than a call to size
). At best, the collection-specific implementation of count()
will be inlined and you'll end up with identical bytecode as if you had written size
. There's no way you end up faster than size
, though.
Regardless, the quote from Kotlin in Action on Reddit was not claiming that the count()
method is faster than the size
method. Rather, it is saying that the Iterable<T>.count(predicate: (T) -> Boolean)
method is more efficient (in execution time and peak memory use) than doing a filter
call and checking size
on the result, since the latter requires the construction of an additional List
to hold the filtered results. That is, the optimal way to write the example in your question would have been this...
nums.count {e -> e > 0}
... and not either of the versions that you tried to benchmark.