1

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?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Cristik
  • 30,989
  • 25
  • 91
  • 127
  • Possible duplicate of [Protocol doesn't conform to itself?](https://stackoverflow.com/q/33112559/2976878) – Hamish Dec 06 '17 at 13:04

1 Answers1

1

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.

Ole Begemann
  • 135,006
  • 31
  • 278
  • 256
  • Hmm... too bad. Is this by design? – Cristik Dec 06 '17 at 12:51
  • It's not a solvable problem for the general case, but it's possible that the compiler will allow this for protocols that don't have static requirements (i.e. no static methods, no initializers, and no associated types). See [Hamish's excellent answer](https://stackoverflow.com/a/43408193/116862) for more details. – Ole Begemann Dec 06 '17 at 15:06
  • Thanks for the other link, indeed very detailed and good answer. – Cristik Dec 06 '17 at 15:29