I have a following method:
private func returnNilIfEmpty<T: Collection>(_ collection: T?) -> T? {
guard let collection = collection else { return nil }
return collection.isEmpty ? nil : collection
}
I’d like to extend the Collection
API to use a computed variable to extract the non-empty value like this:
extension Collection {
var nonEmptyValue: Collection? {
returnNilIfEmpty(self)
}
}
However, I’m getting the error:
Protocol ‘Collection’ can only be used as a generic constraint because
it has Self or associated type requirements
Which is clear, as the outer Collection
can be any collection (e.g. an [Int]
) while the collection inside the returnNilIfEmpty
can be e.g. a String
.
The question is how can I enforce the rule that the Collection
returned via nonEmptyValue
and the one returned via returnNilIfEmpty
of the same type, so that I can get rid of this compiler error?
2
Answers
Using
Self
solves the issue, since it points to the concrete type of the collection:Simplified even further:
It is appropriate to use
Self
here:If e.g. you did
Set([1,2,3]).nonEmptyValue
, you’d expect to get aSet<Int>?
rather than a generalCollection?
(you don’t even know what kind of elements this type contains or anything like that!), wouldn’t you?