On Sat, Jan 2, 2016, at 11:53 PM, Dave Abrahams wrote: > > > On Jan 2, 2016, at 11:26 PM, Kevin Ballard via swift-evolution > > <[email protected]> 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.
FWIW move-only structs (and safe immutable references) are a great solution to this. Rust is a good example. Rust's equivalent to SequenceType is IntoIterator, which has a method into_iter() that consumes the receiver and returns an Iterator. If a sequence is multi-pass, then instead of just implementing it on the type, the IntoIterator trait is also implemented on references to that type (e.g. both `Vec<T>` and `&'a Vec<T>` implement it) and sometimes on mutable references too (`&'a mut Vec<T>`). The multi-pass iterators actually yield references to the elements involved (e.g. the Iterator for `Vec<T>` yields `T`, but the Iterator for `&'a Vec<T>` yields `&'a T`). Similarly Iterator itself can be move-only if it's a single-pass iterator, but for multi-pass iterators the Iterator is either copyable or Clone-able. This scheme means that the type system documents whether a sequence/iterator is multi-pass and statically prevents you from violating that guarantee. Of course, Swift doesn't have move-only structs and it doesn't have immutable references, but thinking long-term this does seem like a great model to be aware of. -Kevin Ballard _______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
