Cristik
Cristik

Reputation: 32809

Protocols with where clause don't work when referring them as protocols

Let's say I have the following infrastructure:

protocol Naming {
    var printer: Printer { get }
    var name: String { get }
}

extension Naming {
    var name: String { return "\(type(of: self))" }

    func printName() {
        printer.print(name)
    }
}

protocol Printer {
    func print(_: String)
}

I have a protocol that exposes a name and a printer, that is used to print the name.

Now, trying to follow MVC, I add these:

protocol ModelInjectable {
    associatedtype Model
    var model: Model { get }
}

extension Naming where Self: ModelInjectable, Self.Model: Naming {
    var printer: Printer { return model.printer }
    var name: String { return model.name }
}

which allows view controllers to specify they allow a model, and in such cases allow them to conform to Naming by simply forwarding the protocol conformance to the model.

This is a simple VC:

class MyViewController: UIViewController, ModelInjectable, Naming {
    let model: MyModel

    required init(model: MyModel) {
        self.model = model
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError()
    }
}

The problem arise when I try to use a protocol for the model:

struct MyModel: Naming {
    let printer: Printer
}

works as expected, however

protocol MyModel: Naming {
}

gives compile errors:

error: type 'MyViewController' does not conform to protocol 'Naming' class MyViewController: NSViewController, ModelInjectable, Naming {

note: candidate has non-matching type 'Printer' var printer: Printer { return model.printer }

note: protocol requires property 'printer' with type 'Printer'; do you want to add a stub? var printer: Printer { get }

From what I can tell, the extension Naming where Self: ModelInjectable, Self.Model: Naming extension is used by the compiler only when using a concrete type. Using a protocol reference doesn't do the trick. Is this a limitation of the compiler, or am I wrongly using the feature?

Upvotes: 1

Views: 368

Answers (1)

Ole Begemann
Ole Begemann

Reputation: 135548

Unlike e.g. Objective-C protocols, a Swift protocol doesn't conform to itself. As a result, protocol MyModel: Naming doesn’t satisfy the Self.Model: Naming constraint of your protocol extension.

Upvotes: 1

Related Questions