3

I have a protocol which declaration looks like this:

protocol RefreshableView where Self: UIView {
    func reload()
}

And it has default implementation which looks as follows:

extension RefreshableView {
    func reload() {
        print("Default implementation")
    }
}

Then if I declare another (empty) extension of UIView conforming to this protocol I get compile-time error stating that UIView does not conform to the protocol.

extension UIView: RefreshableView {}

It should not be a case from my point of view, as default implementation is provided. However if I remove where statement (restriction to the classes which can conform to the protocol) from declaration of the protocol, everything works as expected. Another option to silence this error is to give the same where statement next to default extension declaration, but it feels redundant as I already let compiler know the protocol is supposed for narrow audience. Is there an explanation to this behavior?

The Dreams Wind
  • 8,416
  • 2
  • 19
  • 49
  • `protocol … where Self: …` is quite new syntax, so it's not well done yet – user28434'mstep Sep 11 '19 at 11:38
  • @user28434 it's not widely used but it was in place since swift 3 at least. Most likely it's as old as extension's `where` statement. – The Dreams Wind Sep 11 '19 at 12:00
  • Must be a `Swift` bug. For now you can put the same `where` clause on extension as `extension RefreshableView where Self: UIView`. – Kamran Sep 11 '19 at 13:14
  • 1
    It does feel like a possible bug, but it's also not clear what you're trying to express here. With all three of these in place, RefreshableView and UIView are precisely the same type. Every UIView is a RefreshableView, and every RefreshableView must be a UIView. This feels like a mistake that the compiler might be (inadvertently?) preventing. This "default" implementation of `reload()` becomes precisely an extension on UIView. – Rob Napier Sep 12 '19 at 13:49

1 Answers1

2

What you're saying is that this doesn't compile:

protocol RefreshableView where Self: UIView {
    func reload()
}
extension RefreshableView {
    func reload() {
        print("Default implementation")
    }
}
extension UIView: RefreshableView {
}

As Rob Napier points out in a comment, that's a very odd thing to say, because if UIView itself is going to adopt RefreshableView, then what's the protocol for? The original declaration of the protocol means that only a UIView subclass can adopt RefreshableView, so what the compiler expects is that that's what will happen:

protocol RefreshableView where Self: UIView {
    func reload()
}
extension RefreshableView {
    func reload() {
        print("Default implementation")
    }
}
class MyView: UIView {}
extension MyView: RefreshableView {
}

That is a useful real-world case, and it compiles just fine.

So you could file a bug against your original code, but you have to admit it is a very peculiar edge case to start with; you are saying something that no one would in fact ever say.

matt
  • 515,959
  • 87
  • 875
  • 1,141