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

Reply via email to