[swift-evolution] [Pitch] Remove destructive consumption from Sequence

Jonathan Hull jhull at gbis.com
Thu Jun 23 02:26:20 CDT 2016

What are the actual use-cases where people have needed destructive iterators?  Every time I have thought I wanted it, I ended up wanting multi-pass later.  For example, I had a sequence of random numbers, but ended up having to build a random hash instead so I could reliably re-create that sequence.  The other use-cases I can think of (e.g. markov-chains) would probably end up needing repeatability at some point as well.

The only thing I can think of without an eventual multi-pass requirement would be reading in an input or signal of some sort.

The most troubling thing to me is having the value type be destructive in such a weird way.  

I would like to see Iterator take a more functional approach.  In addition to the mutating next()->T? function, it would be nice to have a non-mutating nextIterator() -> (T, Iterator<T>)?, which non-destructively returns a tuple of the next value and an iterator set to the next step.  This would be nondestructive, so it would probably require pre-calculating the next value early for destructive sequences.  The end result would be that next value is guaranteed to be the same whenever it is called from the non-mutated iterator, but future values may quickly diverge (from separate copies of the value type).

The other alternative would be to make Iterator a reference type.  

I would be ok with either solution.  I would be most in favor of whichever version allows us to build some sort of yielding iterator construct later.  I.e.  I am going to run through this iterator until a condition is met… then later I will pick up where I left off.  This is a useful pattern, especially for things which get destructively consumed.

I would like sequences to always be nondestructive / multi-pass, and gain everything from collectionType except those things which require an end index (e.g. count).  Sequences could be infinite.  Sequences could/would still vend destructively consumed iterators… they would just be required to vend the exact same iterator (which generates the same sequence of values) each time you ask for it.

Then we have collectionType (which should be renamed FiniteSequence), which re-gains count, dropLast, etc….  Basically the same as collectionType today.

What I like about splitting finite and potentially infinite sequences:
1) It allows compiler warnings for .forEach and for-in without break
2) You could build interesting infinite sequences, and then create a finite sequence by adding limits/predicates (e.g.  all prime numbers where x < 250)

FiniteSequence(from: infSequence, boundedBy: 0…100)
FiniteSequence(from: infSequence, stoppingWhen: {$0 % 2 == 0})
FiniteSequence(from: infSequence, maxCount: 1000) //The above may need a maxCount parameter as well (which defaults to Int.max)

Top of my list for interesting infinite sequences would be RandomSequence, which inits with a seed (defaulting to a random seed), and produces a reproducible sequence of random T.


More information about the swift-evolution mailing list