MutableSequence


#1

From what I can tell kotlin-stdlib does not yet have anything like Guava’s Iterables.transform who’s “returned iterable’s iterator supports remove() if the provided iterator does.”

Are there plans for a MutableSequence or something similar who’s iterator() would return a MutableIterator?

This is very handy in iterating over large Iterables and filtering them in-place (i.e. without making a copy).

Example use case:

iterables.forEach { iterable ->
    iterable.asMutableSequence()
            .map(transform)        // e.g. cast to a certain type
            .filter(predicate)     // e.g. filter-out noise
            .forEach(operation)    // e.g. trim some fields, log some messages, etc.
}
assert(iterables.all(predicate))   // e.g. assert something on every iterable

#3

You can filter MutableIterable in-place with removeAll extension method taking a predicate.


#4

That’s true but what if I need to do a transform and then filter then I’ll have to do the transform again before doing an operation on it.


#5

By the way: I find mutable iterators one of the worst design decision of the JDK. I hope that Java will get completely redesigned collections one day. The Scala collections are not perfect, but so much better in so many regards, that they are a strong argument to use Scala.


#6

I see.
So, what operations do you propose to specialize for MutableSequence to return another MutableSequence preserving the behavior of remove operation?


#7

Many of the existing functions could return a MutableSequence (e.g. map, plus, drop, take, filter, minus, requireNonNulls). Others probably not (e.g. distinct, zip).

Contrary to my original example above filter probably should change the underlying collection (i.e. probably shouldn’t filter in place). removeAll could be implemented or a filterOut/filterInPlace.

e.g.

mutableList.asMutableSequence()
        .map(transform)
        .apply { removeAll(predicate) }
        .forEach(operation)

or

mutableList.asMutableSequence()
        .map(transform)
        .filterInPlace(predicate)
        .forEach(operation)

#8

Definitely, filter must not mutate the sequence it was applied to.

What bothers me is that if a MutableSequence is a Sequence, it would have some subset of operations specialized for mutable sequences and the rest operations not specialized, returning plain sequences. Thus, in a chain of sequence operations it becomes very subtle when the type of sequence changes from mutable to read-only.

Also I believe plus operation cannot preserve sequence mutability. Consider a situation when you’re adding a plain sequence to a mutable sequence, what would the resulting sequence be? It is a sequence where remove operation could be called on the first half of elements, and cannot be called on the second half.


#9

Yes, plus would not work in all cases.

I agree with the concern of the subtleties a MutableSequence would introduce. I will give this some more thought.

For now what I am doing is below. Do you have any better ideas on how to go about this perhaps?

with(mutableIterator()) {
    forEach {
        val transformed = transform(it)
        if (predicate(transformed)) {
            remove()
        } else {
            operation(transformed)
        }
    }
}