SE-202, the "Random Unification" proposal, adds the following requirement to the Collection protocol:
protocol Collection {
...
func randomElement<T: RandomNumberGenerator>(using generator: inout T) -> Element?
}
This was added as a requirement because collections with more than Int.max elements (for instance, the range Int.min ... Int.max) would not be able to use a generic implementation. However, this poses a forward-compatibility problem for Collection if we add move-only types in the future, since this requirement cannot be implemented by a collection with move-only elements, since returning the chosen element would require copying it out of the collection. We could make this requirement be consuming, but that's unlikely to be very useful, since picking a single random element out of a collection is unlikely to be the final thing you do with a collection.
There's a more primitive operation we could make a Collection requirement, which instead returns the index of a random element in the collection:
protocol Collection {
func randomIndex<T: RandomNumberGenerator>(using generator: inout T) -> Index?
}
randomElement can then be implemented as an extension method in terms of this requirement (for copyable Collections):
extension Collection {
func randomElement<T: RandomNumberGenerator>(using generator: inout T) -> Element? {
if let index = randomIndex(using: &generator) {
return self[index]
} else {
return nil
}
}
}
Aside from future compatibility with move-only types, randomIndex seems like a better primitive operation, since it can used to build other interesting operations like "insert an element at a random index", "split a collection into random sub-collections", etc. Does this seem like a reasonable amendment to the proposal?