Conditional Conformance: Using 'T' as a concrete type conformance to 'T' is not supported

Viewed 135

I have some very basic code as I'm trying to learn about conditional conformance:

protocol Animal {
    var name: String { get }
}

protocol Social {
    func speak()
}

class Cat: Animal, Social {
    var name: String

    init(name: String) {
        self.name = name
    }

    func speak() {
        print("Meow")
    }
}

class Dog: Animal, Social {
    var name: String

    init(name: String) {
        self.name = name
    }

    func speak() {
        print("Ruff")
    }
}

extension Array: Social where Element: Social {
    func speak() {
        forEach { $0.speak() }
    }
}

let array: [Social] = [Dog(name: "Rocco"), Cat(name: "Gozer")]
array.speak()

When trying to execute the last line array.speak(), I get the error:

"Using 'Social' as a concrete type conforming to protocol 'Social' is not supported."

The way I read the line where I extend Array is this: The array conforms to protocol Social if all elements in the array conform to Social. Is this correct? The following works just fine:

array.forEach { social in
    social.speak()
}

Which makes me believe I've done things right, as far as declaring/initializing the array.

I've looked at multiple posts regarding conditional conformance, but none just give me the basics on how to declare the array (if that's my problem) in order to use it and conform to the protocol Social.

I'm currently reading the book "Swift Apprentice" by Ray Wenderlich and they show everything except actually using the code in an example.

Any help would be greatly appreciated

2 Answers

Change the extension to Element is rather than Element conforms to

extension Array where Element == Social {
    func speak() {
        forEach { $0.speak() }
    }
}

The constraint Array : Social is irrelevant.

A protocol does not conform to itself. Element: Social means that Element must be a type that conforms to Social. Social is not a type that conforms to Social. (Imagine if Social included an init() requirement. What class would Social() return? This is why Social does not conform to itself.)

In this particular case, you probably want both [Social] and [Dog] to get speak(), and in that case you (somewhat unfortunately) have to say so by duplicating the extension, once for Element == Social and once for Element: Social.

Related