Any reason why there's no `toTypedArray` on a `Seq...
# stdlib
d
Any reason why there's no
toTypedArray
on a
Sequence
?
j
it's a weak rationale, but Sequence supports Iterator().toList().toTypedArray() which avoids the lack of size operator for non-deterministic sequences
d
So
toList()
shouldn't be there either... which would make sequences much less useful... my use-case is to pass build
vararg
parameters using
sequence { }
and pass them to a function...
j
vararg is not a sequence but yeah, kotlin stdlib appeears to be written by typing practice alone, when it comes to orthogonal grammar. the typwriter for the Monkey typing out Sequence functions broke midway through
vararg also has blind spots
d
Well, we have to give them credit, stdlib does make life much easier than in Java... 🙂
m
build
vararg
parameters using
sequence { }
just use
iterator { }
, sequences are useless
d
Useless?
p
I recently wrote my own extension function for this
iterates the sequence twice (compute length, convert to array) but that still seems better than converting to an intermediate list. I think this should be considered for addition to the stdlib.
j
why is two sequence iterations better than growing an arraylist once?
p
It's one sequence iteration to compute array length plus another sequence iteration to create the array, vs. one sequence iteration to create the list plus one list iteration to create the array. The former avoids allocating an intermediate list, which is one of the reasons to use a sequence (cf. Java streams).
m
Useless?
Yep, Sequence is a one-time Iterable wrapper. One could just wrap iterators directly.
j
i think to use @elizarov terminology, iterators are not necessarily cold, but sequences are cold.
m
`Iterable`s are not necessary cold. `Iterator`s are.
e
Yes. The idea of a separate sequence type is to distinguish hot/cold (or eager/lazy) sources on a type level. So if you do a
filter
on an
Iterable
, for example, you get
List
as a result in an eager fashion, but if you call
filter
on
Sequence
, you get a sequence as a result in a cold (lazy) way. So, while
Sequences
is simply a wrapper it is a very useful one, because it affects the way all the operators work.
m
Extensions on
Sequence
are useful. Sequences themselves aren't.
e
But extensions of it are the sole reason this type exists. There’s no other type to put those extensions on.
It is type-level marker for coldness.
m
Iterator
.
e
No. You cannot have useful extensions on iterator. Iterator is hot & single-use.
It is already iterating. It is not a type you should be placing useful transformations on.
m
Sequences are effectively single use iterator factories. What's 'hot' inside iterators?
e
Sequences are not single-use.
They are cold
Get an iterator to a list of lines being read from a file and you’ll immediately see what’s hot about iterator.
Same problem with Java stream. Bad, bad design. Don’t be like Java.
m
They are effectively single-use. You make
iterable.asSequence().transforms().toList()
and that's it. Same as
iterable.iterator().transform().collectToList()
but with more overhead.
I don't see why file lines
Iterator
is hotter than a
Sequence
.
e
They are not single use. They are cold & multi-use, Take.
listOf(…).filter { … }
and you can use as many times and you want
m
But you typically don't want. If you want to, you collect to list.
e
Because a
Sequences
of file lines does not keep the file open. It opens a file only when you start iterating it.
m
Okay, what about opening a file after first `hasNext()`/`next()` ? Is it so complicated?
e
It is just wrong and inefficient way to do it.
So, no reason to have it in stdlib.
m
Eagerly loading is wrong and inefficient. And I don't see any reason why 'cold' iterator could be considered inefficient.
e
Iterators are not cold. They have state, they are mutable, they are error-prone to work with. Cold entities don’t have state. They are immutable, they are much safer to work with. It is that simple
m
Why having stateless transform factories? I don't want a factory, I need a single transform in 146% cases. In other -46% cases I'd collect iterator to list.
e
That’s fine. You are not prevented to do that. Writing
asSequence()… toList()
is not longer as
iterator()…toList()
would have been. The former is simply better design in overall, but you can still use it just as well.
m
It is not longer but produces more garbage.
e
If you care about garbage that much, I’d suggest you to write low-level code with loops & arrays. The goal of Kotlin stdlib is not to reduce garbage, but to make programming safer & easier.
and less error-prone.
However, we do have some long-term plans to automatically compile sequence-based transformation chains into efficient low-level code without extra allocations. New JVM IR BE will enable these kinds of things.
m
I don't like the idea of overengineering and creating objects you're not gonna use. Sidenote: iterator transforms could be crossinline, returning new anonymous iterator class instance and making devirtualization easier.