why is a `Sequence` not `Iterable`?
# announcements
t
why is a
Sequence
not
Iterable
?
m
vs. sequence
their underlying structure for handling collections is fundamentally different,
t
I doubt that's the reason. a
Sequence
provides all the methods, an
Iterable
must provide, too
(in fact it must provide only ONE method
itetator
)
m
I mean, just read the link
😆 1
s
You can make a Sequence like an Iterable returning an Iterator. However, the
hasNext()
methods on that Iterator will cause the backing Sequence to realize at least its next element (ie its generator/builder will
yield
) to be able to look-ahead. This can have side-effects, as where the
hasNext()
of a ‘plain’ Iterable’s Iterator does not have side effects, since it can easily look ahead.
🚫 1
t
well isn't it wrong already to provide the
iterator()
?
s
Ah.. I see, the ‘iterator()’ is already there, still be careful with the ‘hasNext()’ 🙂
t
it feels very inconsitent not to implement an interface that actually is implemented, but then arguing it can't be implemented because one of the methods behaves incorrectly
s
For
Collection.asSequence()
sequences, the
hasNext()
is fine. It may get a bit problematic if you build your own (
=sequence { … }
) .
m
I think both iterable and sequence should implement from an overlying interface that holds the functions for both, but one is not the other
why isn't
set
a
list
is the same question
t
no its not
they behave compeltly differently
s
On those, you have different methods, so no, it is not the same question.
d
Correct, and
Iterable
and
Sequence
also behave completely differently.
Iterable
=> eager
Sequence
=> lazy
☝️ 2
s
For the iterator() from a Collection or a Sequence, the methods are exactly the same. For a Sequence, the lazy generation of it can have some side effects with respect to its iterator()’s hasNext method
t
no the bave the same according to the interface
d
They do not...
t
then again i argue, it's simply very inconsistent
s
Both ’hasNext()’s will return true if there is a next item. However, hasNext() on the Sequence may have a side-effect.
t
The documentation of
Iterable
does not even mention how the
Iterator
returned by
iterator()
hast to behave
also the documentation of
Iterator
does not mention
hasNext
may not have side effects
s
I read it somewhere in some documentation… I just don’t remember where. 🙂
And it is true; calling
hasNext()
on an iterator from a Sequence may cause its sequence-builder to resume from a suspending
yield()
… which may or may not cause a side effect depending on your builder; the hasNext() call may effectively generate the next element/item.
k
no the bave the same according to the interface
Well, they do not behave the same. Both have to give an iterator as thats how they mesh with for loops.
Also on Iterable there are a bunch of extension functions that run eagerly. If Sequences would also extend Iterable, there wouldn't be an easy clear way to see if an extension function would run eager or lazy, which would make looking at code very hard.
i
Sequence
and
Iterable
are structurally the same interfaces. The difference is how extension operations are implemented upon them.
t
@ilya.gorbunov can you explain that a little more?
they do implement strucrally the same interface AND (observed from the outside) do share a similar behavior
d
I don't get where "share a similar behavior" is coming from.
Iterable
is eager,
Sequence
is lazy. That is not similar behavior.
t
its coming from they are fullfuilling the very same behavior and you cannot observe any difference from the outside
its one of the most basic features of OOP to code against interfaces not implementation
d
"the very same behavior" - no they are not.
Interfaces provide a contract, not just a pile of methods.
Sequence
contract says: This operates lazily.
Iterable
contract doesn't say that.
t
well then why does a
Sequence
provide the method
iterator()
maybe it is because a seqeunce inherently is iterable?
d
Because that's how you get elements out of it?
Yes, it is iterable (the verb), not
Iterable
(the interface).
t
OF COURSE it is
if you were right than
List
and
Set
shouldn't share the same itnerface because they differ in implementation
d
... no? The both implement
Collection
, whose contract they follow perfectly fine.
t
no they do not
d
How so? Which part of the contract do they violate?
t
the one is a
Set
containing it only once they other is a`List` containing it multiple times
if you think that argument is bollock: we finally she a feeling 😉
d
So?
Collection
does not prohibit either of those
t
yes and
Iterable
doesn't say that evaluation must be eager
d
Correct, it doesn't. But usually it is. This is called pragmatism.
And its one of Kotlin's core design goals.
t
i think you are too much like "this must be correct because if it wasn't it would be implemented differently"
d
How would you do it?
"Just implement Iterable on Sequence" doesn't work, by the way
t
of course i would implement
Iterable
because everything else of the implementation says it's itereable. And if i were sure it's really different i would NOT provide an
iterator()
tht returns the good old java
Iterator
d
If you implement
Iterable
you now have two
filter
extensions on
Sequence
, the eager
Iterable
version (that returns a List) and the lazy
Sequence
version that returns a
Sequence
. Thats not very user friendly.
Note that the "this is iterable" contract in Kotlin is not "implements Iterable". It is "has an
operator fun iterator(): Iterator
"
t
ah so that's finally a point made. In fact we WOULD think it's
Iterable
but cannot implement it because else we would get trouble regardig extensions
that's something i can understand 😉
thank you 😄
k
Also another thing, if you could and were to call the
Iterable.map()
function on a
Sequence
it could crash the JVM as a Sequence could generate an infinite amount of elements, and you only have a finite amount of RAM.
So yeah, it's to keep the extension function away from eachother.
t
Yeah but that's the same wit java's
Stream
. Also again, the interface does not say anything about there must be a finite amount of elements in the
Iterable
of ven an amount of finite elements that fit into the heap 😉
k
A
Stream
is actually very similar to a Kotlin
Sequence
. And it also doesn't extend
Iterable
t
that's indeed an interesting point