0

After reading an discussion about using Self in protocol, I did an experiment (see code below). I thought the code would fail to compile because, from my understanding, for class B to conform to Copyable protocol, it should have init(_ instance: B), which I didn't define. But the code actually works.

I wonder why? Thanks for any explanation.

 1  import Foundation
   
 2  protocol Copyable: class {
 3      init(_ instance: Self)
 4  }
   
 5  class A: Copyable {
 6      var x: Int
 7      
 8      init(x: Int) {
 9          self.x = x
10      }
11      
12      required init(_ instance: A) {
13          self.x = instance.x
14      }
15  }
   
16  class B: A {
17      var y: Int
18      
19      init(x: Int, y: Int) {
20          self.y = y
21          super.init(x: x)
22      }
23      
24      required init(_ instance: A) {
25          self.y = 1
26          super.init(instance)
27      }
28  }
   
29  var a = A(x:1)
30  var b = B(a)
rayx
  • 1,329
  • 10
  • 23

1 Answers1

2

According to the documentation Self in this case will be A since A is the one conforming to the protocol, B is only doing it indirectly as a subclass of A.

So when A conforms to Copyable you are saying that A and all its subclasses must have an init(_ instance: A)

In a protocol declaration or a protocol member declaration, the Self type refers to the eventual type that conforms to the protocol.

You can actually test this by removing the required init(_ instance: A) init and you will get an error even if you have an init(_ instance: B), so since A is the class conforming to the protocol you must have an init where the instance argument is A

Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52
  • Thanks, @Joakim-Danielson. It's a bit hard to understand what exactly "the eventual type that conforms to the protocol" in the doc means without the experiment. BTW, what I really wanted was to look for some way to define a protocol for the behavior I expected (that is, a class and all its subclasses have their own `init(_ instance )`. So it seems there is no way to do that. – rayx Apr 05 '21 at 00:41
  • @rayx note that from a caller’s perspective, this is no different from what you want. If I have a `T` that is constrained to `Copyable`, its initialiser would appear as `init(_: T)`, even if `T` is B – Sweeper Apr 05 '21 at 01:06
  • @Sweeper I see your point. The issue is that it can't enforce what I'd like to have - I want each subclass **must** implement their own `init(_ instance )`. That's why I said it's not powerful enough. – rayx Apr 05 '21 at 01:10
  • @rayx I don’t know how your full classes look but one option is to skip the superclass, then all classes needs to conform to the protocol with their own type. – Joakim Danielson Apr 05 '21 at 05:54
  • Thank @JoakimDanielson. That's one possible way to do it, though I took another route - I just gave up putting that interface in protocol. The more I use protocol, the more I realize it has its own limitation. I think I should use it for what it's good at and avoid fighting it (for example, using `Self` with subclass). – rayx Apr 05 '21 at 10:10