# Is this the right way subclasses should handle a base class conforming to a protocol initializer?

**URL:** <https://forums.swift.org/t/is-this-the-right-way-subclasses-should-handle-a-base-class-conforming-to-a-protocol-initializer/39979>\
**Category:** Using Swift\
**Tags:** inheritance, protocols, class, conformance\
**Created:** [September 3, 2020, 1:18am UTC](https://forums.swift.org/t/is-this-the-right-way-subclasses-should-handle-a-base-class-conforming-to-a-protocol-initializer/39979 "2020-09-03T01:18:19Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![CTMacUser](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ctmacuser/32/1802_2.png) [@CTMacUser](https://forums.swift.org/u/CTMacUser)\
**Post date:** [September 3, 2020, 1:18am UTC](https://forums.swift.org/t/is-this-the-right-way-subclasses-should-handle-a-base-class-conforming-to-a-protocol-initializer/39979/1 "2020-09-03T01:18:19Z")

</div>

Let's start with:

```
/// A type where an instance may be an independent copy of another instance,
/// with various levels of copying for sub-objects.
protocol Cloner {
    /// Creates a copy of the given instance, where sub-objects are themselves
    /// cloned to the given depth.
    init?(copying original: Self, toDepth depth: Int)
}

```

And I make a sample class that conforms to `Cloner`:

```
class Sample1: Cloner {
    init() {}
    required convenience init?(copying original: Sample1, toDepth depth: Int) {
        self.init()
    }
}

```

Where I can choose whether the initializer copied from `Cloner` is `convenience` or not.

The oddity is when I make a derived class:

```
class Sample2: Sample1 {
    var value: Int
    init(value: Int) {
        self.value = value
        super.init()
    }
    required convenience init?(copying original: Sample1, toDepth depth: Int) {
        guard let original2 = original as? Sample2 else { return nil }
        self.init(value: original2.value)
    }
}

```

Note that the first parameter is of the `Sample1` type, not `Sample2`! In fact, if I make one that matches `Sample2` for the sake of `Cloner`, the compiler insists on making the `Sample1` variant above.

I was really stumped. Until I made a separate derived class `Sample3` from `Sample1`, then made another one, `Sample4`, that derived from `Sample3` instead. Neither `Sample3` nor `Sample4` had any members; so they inherited the ones from `Sample1`. When I created some sample objects in the playground, I was surprised as the suggestions.

For `Sample1`, I got suggestions for the empty and copying initializers. For `Sample2`, I got the single-`Int` initializer, the copying initializer with `Sample1`, and then an **additional** copying initializer with `Sample2` instead. Analogous results happened when creating `Sample3` and `Sample4` objects. (With `Sample4`, only the `Sample1` and `Sample4` versions of the copying initializer appeared.). So the rule seems to be that for class types, the first class to incorporate a protocol with initializer requirements involving `Self` gets the parameter type named after itself. Derived classes must still use the first base class in the type signature. However, the function suggestions will create two versions of the initializer, one using the base class for the parameter and one with the current class for the parameter.

Am I guessing right? Why was it done this way? Why can't I fill in `Self` with the actual current class and have it count? My example uses a fail-able initializer, so I have a policy in place if the `Sample1` parameter gets an argument of a more derived type. But what are derived classes supposed to do when the initializer is non-fail-able and but the base-class parameter is called with a different class object? (For instance, what if my initializer was non-fail-able and I created a `Sample2` object, but filled in the `Sample1` parameter with a `Sample4` argument?)

---

<div class="post-metadata">

**Author:** ![Lantua](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/lantua/32/8868_2.png) [@Lantua](https://forums.swift.org/u/Lantua)\
**Post date:** [September 3, 2020, 12:06pm UTC](https://forums.swift.org/t/is-this-the-right-way-subclasses-should-handle-a-base-class-conforming-to-a-protocol-initializer/39979/3 "2020-09-03T12:06:11Z")

</div>

Note that `Sample2` is still a subclass of `Sample1`, so you can still do:

```swift
let meta: Sample1.Type = Sample2.self
let original = Sample1()
meta.init(copying: original, toDepth: 1) // nil

```

And `meta.init` needs to have `original` be `Sample1`, not `Sample2` or `Self`.

---

<div class="post-metadata">

**Author:** ![jrose](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jrose/32/408_2.png) [@jrose](https://forums.swift.org/u/jrose)\
**Post date:** [September 3, 2020, 3:34pm UTC](https://forums.swift.org/t/is-this-the-right-way-subclasses-should-handle-a-base-class-conforming-to-a-protocol-initializer/39979/4 "2020-09-03T15:34:55Z")

</div>

Note that this problem comes up because there are two Sample1 "input" types in play now: the implicit `self` for the class, and the `original` argument. You can't get rid of `self`, but you _can_ get rid of the argument by making this an instance method instead:

```swift
protocol Clonable {
  func copy(toDepth depth: Int) -> Self?
}

```

---

<div class="post-metadata">

**Author:** ![CTMacUser](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ctmacuser/32/1802_2.png) [@CTMacUser](https://forums.swift.org/u/CTMacUser)\
**Post date:** [September 3, 2020, 10:18pm UTC](https://forums.swift.org/t/is-this-the-right-way-subclasses-should-handle-a-base-class-conforming-to-a-protocol-initializer/39979/5 "2020-09-03T22:18:19Z")

</div>

I tried playing around with this, but I discovered:

1. You can't make non-initializers `required`. So you can't enforce the derived classes of a conforming class to themselves define a custom `copy(toDepth:)`. Now, my tryout did specify that an initializer call for the return value requires said initializer to be `required`, but I got around that by forcing the issue with "`as!`" (or "`as?`").
2. My original version of the cloning protocol had a derived protocol changing the "?" to a "!". When I refine your version with a protocol that returns "`Self!`", it doesn't work right. Conforming to the protocol requires the class to define both versions (`copy(toDepth:) -> Self?` and `copy(toDepth:) -> Self!`), but then the compiler complains about invalid re-declarations (since the methods only differ in the "?" vs. "!" status of the return value).

Hmm, technically I don't need the version that returns "!"; I could just make it a marker protocol without any new members.

---

<div class="post-metadata">

**Author:** ![jrose](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jrose/32/408_2.png) [@jrose](https://forums.swift.org/u/jrose)\
**Post date:** [September 3, 2020, 10:43pm UTC](https://forums.swift.org/t/is-this-the-right-way-subclasses-should-handle-a-base-class-conforming-to-a-protocol-initializer/39979/6 "2020-09-03T22:43:26Z")

</div>

The `!` / `?` mismatch sounds like a bug, can you file that separately?

---

<div class="post-metadata">

**Author:** ![CTMacUser](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ctmacuser/32/1802_2.png) [@CTMacUser](https://forums.swift.org/u/CTMacUser)\
**Post date:** [September 4, 2020, 2:47am UTC](https://forums.swift.org/t/is-this-the-right-way-subclasses-should-handle-a-base-class-conforming-to-a-protocol-initializer/39979/7 "2020-09-04T02:47:24Z")

</div>

To show exactly what happened, here's my sample protocols:

```
protocol Clonable {
    func copy(toDepth depth: Int) -> Self?
}
protocol StronglyClonable: Clonable {
    func copy(toDepth depth: Int) -> Self!
}

```

and my sample classes start as:

```
class SampleX { init() {} }

```

When I add `Clonable` conformance to one and `StronglyClonable` to the other, I get the following stubs:

```
class Sample1: Clonable {
    func copy(toDepth depth: Int) -> Self? {
        return Sample1() as? Self
    }
    init() {}
}

class Sample2: StronglyClonable {
    func copy(toDepth depth: Int) -> Self! {
        return (Sample2() as! Self)
    }
    func copy(toDepth depth: Int) -> Self? {
        return Sample2() as? Self
    }
    init() {}
}

```

(I filled in the internals to the methods.). The head to the second method of `Sample2` is marked with:

```
Invalid redeclaration of 'copy(toDepth:)'

```

Created [SR-13496](https://bugs.swift.org/browse/SR-13496) ("Derived protocol that updates an override with a different Optional variant isn't properly handled"). The way the website wants us to input code is weird (It's not Markdown); I have never been able to figure it out so someone needs to make to code sample formatting work.

---

<div class="post-metadata">

**Author:** ![suyashsrijan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/suyashsrijan/32/5292_2.png) [@suyashsrijan](https://forums.swift.org/u/suyashsrijan)\
**Post date:** [September 4, 2020, 3:26am UTC](https://forums.swift.org/t/is-this-the-right-way-subclasses-should-handle-a-base-class-conforming-to-a-protocol-initializer/39979/8 "2020-09-04T03:26:13Z")

</div>

I reduced that to:

```swift
struct S {
  func f(a: Int) -> String? { return nil }
  func f(a: Int) -> String! { return "" }
}

```

I get the same error.

---

<div class="post-metadata">

**Author:** ![Jumhyn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jumhyn/32/3891_2.png) [@Jumhyn](https://forums.swift.org/u/Jumhyn)\
**Post date:** [September 4, 2020, 3:55am UTC](https://forums.swift.org/t/is-this-the-right-way-subclasses-should-handle-a-base-class-conforming-to-a-protocol-initializer/39979/9 "2020-09-04T03:55:14Z")

</div>

> [@suyashsrijan](#):
>
> ```swift
> struct S {
> func f(a: Int) -> String? { return nil }
> func f(a: Int) -> String! { return "" }
> }
> 
> ```
> 
> I get the same error.

I think since [SE-0054](https://github.com/apple/swift-evolution/blob/master/proposals/0054-abolish-iuo.md) this is expected behavior. I should probably be possible for `foo() -> T!` to act as a witness for `foo() -> T?`, though...

---

<div class="post-metadata">

**Author:** ![CTMacUser](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ctmacuser/32/1802_2.png) [@CTMacUser](https://forums.swift.org/u/CTMacUser)\
**Post date:** [September 4, 2020, 4:08am UTC](https://forums.swift.org/t/is-this-the-right-way-subclasses-should-handle-a-base-class-conforming-to-a-protocol-initializer/39979/10 "2020-09-04T04:08:38Z")

</div>

Yeah, the two methods probably shouldn't be simultaneously allowed. But for protocols, a `init?` or `init!` requirement can be actually implemented by the other (or by a non-fail-able `init`). The problem in this sub-thread is that swap isn't allowed for non-initializers; the derived protocol's change to "!" created a new requirement instead of overlaying the base protocol's requirement.
