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?