[swift-evolution] Proposal: Add SequenceType.first

Kevin Ballard kevin at sb.org
Tue Jan 5 18:43:16 CST 2016

On Tue, Jan 5, 2016, at 03:43 PM, Jordan Rose wrote:
>> On Jan 2, 2016, at 23:53, Dave Abrahams via swift-evolution <swift-
>> evolution at swift.org> wrote:
>>> On Jan 2, 2016, at 11:26 PM, Kevin Ballard via swift-evolution <swift-
>>> evolution at swift.org> wrote:
>>> On Sat, Jan 2, 2016, at 11:17 PM, Brent Royal-Gordon wrote:
>>>>> `buffered` is no more problematic than `lazy` is. In fact, calling
>>>>> `buffered` actually doesn't have any side-effects at all (it can
>>>>> avoid fetching the first element until you call `first` on the
>>>>> result of `buffered`).
>>>> If `seq` is a single-pass sequence, then `seq.buffered.first` will
>>>> consume an element from `seq`, even though you only accessed two
>>>> properties. That's why I call it problematic.
>>>> (If calling `buffered` somehow rendered the original sequence
>>>> unusable—for instance, if we had some way to express that the
>>>> `BufferedSequence` takes unique ownership of its base—this wouldn't
>>>> bother me as much.)
>>> If `sequence` is a single-pass sequence, wrapping it in any other
>>> sequence type and then doing anything with that other sequence type
>>> makes the original sequence unusable (or rather, you can still use
>>> it but the elements yielded from any further access to the original
>>> sequence can be completely arbitrary).
>>> And for the record we already have precedent for the specific case
>>> of `seq.prop1.prop2` destructively consuming the original sequence:
>>> `seq.lazy.array`.
>> Yes, and there are arguments for dropping “.array” as a property.
>> The convention is that “conversions” (ill-defined, I know) use
>> constructor syntax, and we are currently heading towards the
>> elimination of "convenience” interfaces that duplicate functionality,
>> so we might end up with Array(seq).
>> All that said, single-pass Sequences are just weird in that they get
>> mutated without calling any mutating methods on them; you mutate them
>> by calling a mutating method on a separate generator instance.  In
>> other words, they fundamentally have reference semantics. There may
>> be some better way to address this whole area, but we’ll have to go
>> much deeper than merely poking at the question of a `.first`
>> property.
> Should "generate()" be a mutating method on SequenceType, then? And a
> non-mutating one on CollectionType, obviously.

No, that would make SequenceType too hard to use. Specific sequences
could still have non-mutating generate() methods, but any kind of
generic Sequence wrapper would be forced to use a mutating generate(),
and that would make the ergonomics of using them awful. For example,
instead of

for x in seq.lazy.map(f) { ... }

you'd have to say

var seq2 = seq.lazy.map(f)    for x in seq { ... }

And in the end, it wouldn't really solve anything anyway, because you
can still implement single-pass sequences using a non-mutating
generate() anyway (either the sequence is a class, or it uses a class or
UnsafeMutablePointer internally, or it manipulates global state, e.g. a
sequence that reads lines from stdin with readLine()).

-Kevin Ballard
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160105/47ba0dba/attachment.html>

More information about the swift-evolution mailing list