swiftswift-protocolsprotocol-oriented

Extending a constrained protocol for an array argument is not possible


I'm going to explain it by an example. We have a protocol for force having firstName and lastName like:

protocol ProfileRepresentable {
    var firstName: String { get }
    var lastName: String { get }
}

the type we are going to use have these two, but in an optional form:

struct Profile {
    var firstName: String?
    var lastName: String?
}

so after conforming to the ProfileRepresentable, we will extend the ProfileRepresentable and try to return the value and a default one for nil state:

extension Profile: ProfileRepresentable { }
extension ProfileRepresentable where Self == Profile {
    var firstName: String { self.firstName ?? "NoFirstName" }
    var lastName: String { self.lastName ?? "NoLastName" }
}

So far so good

Now there is a similar flow for a list of Profiles.

protocol ProfilerRepresentable {
    var profiles: [ProfileRepresentable] { get }
}

struct Profiler {
    var profiles: [Profile]
}

First issue

conforming to ProfilerRepresentable does NOT automatically done the implementation as expected (since Profile already conforms to ProfileRepresentable)

extension Profiler: ProfilerRepresentable { }

Second Issue

Following the previous pattern, extending ProfilerRepresentable is not working as expected and it raises a warning:

⚠️ All paths through this function will call itself

extension ProfilerRepresentable where Self == Profiler {
    var profiles: [ProfileRepresentable] { self.profiles }
}

How can I achieve the goal for arrays by the way ?


Solution

  • You can achieve it by mapping the extension's profile result to the needed protocol so that the compiler can understands it:

    extension ProfilerRepresentable where Self == Profiler {
        var profiles: [ProfileRepresentable] { self.profiles.map { $0 as ProfileRepresentable } }
    }