Reputation: 8053
I am creating an extension to Collection
which returns a SubSequence
. However, if the function's condition isn't valid I want to return an empty SubSequence
instead of nil.
How can I return an empty SubSequence
in an extension to Collection
?
// basic example:
extension Collection {
func myFunction(condition: Bool) -> SubSequence {
guard condition else {
return *EmptySubSequence*
}
...
}
}
This would be very easy if I just did an extension on a concrete type, but before I limit my extension to a specific type, I would like to know if it can apply to Collection
itself.
The best I've found is prefix(0)
will return a SubSequence
of length 0.
Upvotes: 2
Views: 337
Reputation: 299505
While I believe Leo's answer is very helpful, I wouldn't use it in this case. There is no need to add an additional requirement such as RangeReplaceableCollection, which also adds a replaceSubrange
requirement. Adding these requirements limits the extension more than needed. For example, Range is not a RangeReplaceableCollection. (If you really only plan to ever call this on Array, then I recommend making that explicit and forget about Collection.)
Creating a "fresh" subsequence means that it becomes unrelated to the original collection, and that breaks the meaning of the indices. Calling init
is going create something with a "zero-like" start index that may not be compatible with the collection you're working on. You can't safely compare indices from different collections, even of the same type.
Sweeper's recommendation of prefix(0)
is better, but I think anchoring to the beginning isn't helpful for common algorithms that would need this.
Instead, I recommend a subsequence at the end of the collection: self[endIndex...]
.
Consider an algorithm for myFunction
that processes some portion of the collection, possibly skipping over some part, and returning the first "important" part (i.e. a first stage of a tokenizer that skips over whitespace). The endIndex
would naturally tell you the last place it looked, and allow you to start the next search at that point. Returning an empty subsequence from this collection means that the indices are always compatible. You can always safely set startSearchingFrom = result.endIndex
, even in the case that it's empty.
In most cases, getting the indices right won't matter. But in most cases, you probably just wanted to use this on Array anyway and it didn't need to be generic. If you are going to make it generic, IMO you should make sure to keep all the semantics of the types you're working on, and that means getting the indices right.
Upvotes: 1
Reputation: 236458
If you need to initialize an empty collection you should extend RangeReplaceableCollection
instead of Collection
. RangeReplaceableCollection
requires the types which conform to it to implement an empty initializer.
extension RangeReplaceableCollection {
func myFunction(condition: Bool) -> SubSequence {
guard condition else {
return .init()
}
// ...
}
}
Upvotes: 4