[swift-evolution] About the PermutationGenerator
plx
plxswift at icloud.com
Wed Jan 13 11:23:53 CST 2016
> On Jan 12, 2016, at 11:55 AM, Jordan Rose <jordan_rose at apple.com> wrote:
>
>
>> On Jan 11, 2016, at 18:35 , plx via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>
>>> RandomElementSequence: As you say, this type is copyable, but its iteration is destructive: you can't get back to a previous state via any sort of Index. But that's not a distinction between Sequence and Generator today; there are some Generators that are perfectly copyable and others that are not. (Ideally, the ones that aren't would be made into classes.) If all you have is a generic Generator, you can only iterate it once…but the same is true of Sequence. Knowing the concrete type
>>
>> ^ did something get edited out here?
>
> Oops, yes. "Knowing the concrete type is the only way to guarantee that multiple iteration is safe." And then:
>
>>> Sure, you could come up with a new protocol, MultipassSequence, but you could just as easily have a MultipassGenerator that just means "this generator is safe to copy". (That's basically InputIterator vs. ForwardIterator <http://en.cppreference.com/w/cpp/iterator> in C++.)
>
>
>
> Also:
>
>> It also highlights that `ForwardIndexType` and `GeneratorType` are suspiciously similar, and would be even more so in a “collections move indices” world (e.g. SR-122, which I hope is adopted in some form).
>
> I guess this is true, in that both produce a single successor, but (a) ForwardIndexType is non-destructive whereas GeneratorType may be, and (b) in that new model, ForwardIndexType does not know its successor whereas GeneratorType does.
It’s not so much that they both produce a single successor; it’s that both of them can wind up with most of their “interesting" logic essentially-shared.
Consider the following thought experiment:
protocol AlternativeCollectionType {
typealias InternalPosition: Equatable
typealias Item // so-named so as to avoid some later circularity
var startPosition: InternalPosition { get }
var endPosition: InternalPosition { get }
subscript(position: InternalPosition) -> Item { get }
// - requires: `position != endPosition`
func successorFor(position: InternalPosition) -> InternalPosition
}
// assume `==` just examines position (which seems fair here):
struct ConcretePosition<C:AlternativeCollectionType> : Equatable {
typealias Element = C.Item
private let collection: C
private var position: C.InternalPosition
func isEndPosition() -> Bool {
return position == collection.endPosition
}
func dereference() -> Element? {
if isEndPosition() { return nil }
return collection[position]
}
private func nextPosition() -> C.InternalPosition {
precondition(!isEndPosition())
return collection.successorFor(position)
}
}
extension ConcretePosition : ForwardIndexType {
func successor() -> ConcretePosition<C> {
return ConcretePosition<C>(
collection: collection,
position: nextPosition()
)
}
}
extension ConcretePosition: GeneratorType {
mutating func next() -> Element? {
guard let element = dereference() else { return nil }
position = nextPosition()
return element
}
}
I think the *similarity* under this organization is pretty straightforward; although `successor()` and `next()` are definitely *not* identical, they can both be implemented as operations on the same base type, with a lot the logic being essentially common to both (that’s the part written here as `nextPosition`, which simply calls the collection's `successorFor`).
Note that under Swift’s current organization, that common logic winds up manually-inlined into both `next` and `successor`, often in ways that make the commonality harder to spot.
The above experiment’s connection-with “collections move indices” is also I hope pretty easy to spot; if you accept the premise that most concrete `ForwardIndexType` implementations will in fact need a back-reference — or the moral equivalent thereof — to be able to implement the ostensibly stand-alone `successor()`, then it seems reasonable to consider the possibility that the stand-alone `successor` is actually the special-case (a very handy case, but still a special case); if you don’t accept that premise, we’ll have to agree to disagree.
Thanks again for the consideration and the considered replies. I will be finishing up a proposal relating to this topic and it’ll be much the better for having received your responses (and Dmitri’s, also).
>
> Jordan
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160113/8c2b14fd/attachment.html>
More information about the swift-evolution
mailing list