Both of these interfaces define only one method
public operator fun iterator(): Iterator<T>
Documentation says Sequence
is meant to be lazy. But isn't Iterable
lazy too (unless backed by a Collection
)?
Both of these interfaces define only one method
public operator fun iterator(): Iterator<T>
Documentation says Sequence
is meant to be lazy. But isn't Iterable
lazy too (unless backed by a Collection
)?
The key difference lies in the semantics and the implementation of the stdlib extension functions for
Iterable<T>
andSequence<T>
.For
Sequence<T>
, the extension functions perform lazily where possible, similarly to Java Streams intermediate operations. For example,Sequence<T>.map { ... }
returns anotherSequence<R>
and does not actually process the items until a terminal operation liketoList
orfold
is called.Consider this code:
It prints:
Sequence<T>
is intended for lazy usage and efficient pipelining when you want to reduce the work done in terminal operations as much as possible, same to Java Streams. However, laziness introduces some overhead, which is undesirable for common simple transformations of smaller collections and makes them less performant.In general, there is no good way to determine when it is needed, so in Kotlin stdlib laziness is made explicit and extracted to the
Sequence<T>
interface to avoid using it on all theIterable
s by default.For
Iterable<T>
, on contrary, the extension functions with intermediate operation semantics work eagerly, process the items right away and return anotherIterable
. For example,Iterable<T>.map { ... }
returns aList<R>
with the mapping results in it.The equivalent code for Iterable:
This prints out:
As said above,
Iterable<T>
is non-lazy by default, and this solution shows itself well: in most cases it has good locality of reference thus taking advantage of CPU cache, prediction, prefetching etc. so that even multiple copying of a collection still works good enough and performs better in simple cases with small collections.If you need more control over the evaluation pipeline, there is an explicit conversion to a lazy sequence with
Iterable<T>.asSequence()
function.Completing hotkey's answer:
It is important to notice how Sequence and Iterable iterates thought your elements:
Sequence example:
Log result:
filter - Map - Each; filter - Map - Each
Iterable example:
filter - filter - Map - Map - Each - Each