Home > Blockchain >  Swift Collection API: extend with a computed variable: type error
Swift Collection API: extend with a computed variable: type error

Time:12-23

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?

CodePudding user response:

It is appropriate to use Self here:

extension Collection {
    var nonEmptyValue: Self? {
        returnNilIfEmpty(self)
    }
}

If e.g. you did Set([1,2,3]).nonEmptyValue, you'd expect to get a Set<Int>? rather than a general Collection? (you don't even know what kind of elements this type contains or anything like that!), wouldn't you?

CodePudding user response:

Using Self solves the issue, since it points to the concrete type of the collection:

import Foundation

extension Collection {
    var nonEmptyValue: Self? {
        returnNilIfEmpty(self)
    }
}

func returnNilIfEmpty<T: Collection>(_ collection: T?) -> T? {
    guard let collection = collection else { return nil } // nil -> return nil
    return collection.isEmpty ? nil : collection // return nil if empty
}

Simplified even further:

import Foundation

extension Collection {
    ///
    var nonEmptyValue: Self? {
        self.isEmpty ? nil : self
    }
}
  • Related