"override" on initializers seems overly constraining?

The rules for the override keyword on non-required initializers seem overly constraining as they prevent expressing shadowing when parameters match, but other aspects of the declaration differ:

class Base {
    init() {}
}

class ThrowingDerived: Base {
    // error: overriding declaration requires an 'override' keyword
    // error: cannot override non-throwing initializer with throwing initializer
    init() throws { super.init() }
}

class FailableDerived: Base {
    // error: overriding declaration requires an 'override' keyword
    // error: failable initializer 'init()' cannot override a non-failable initializer
    init?() { return nil }
}

I think these derived initializers should be considered shadowing, not overriding (which introduces the additional constraints) since the base initializer is not required. The only way I found to achieve the shadowing semantics is to introduce a dummy intermediate base with different parameters:

class Base {
    init() {}
}

class Dummy: Base {
    // Hides 'init()' so derived classes can redeclare it
    init(_: Void = ()) { super.init() }
}

class ThrowingDerived: Dummy {
    init() throws { super.init() }
}

class FailableDerived: Dummy {
    init?() { return nil }
}

Is this a defect in the language (in which case I'd promote this to a pitch), or is there additional syntax I'm unaware of?

1 Like

It seems nothing ever improved the situation. (The init can at least be fileprivate though, so you can't instantiate Dummy elsewhere). Typed errors don't help.

https://github.com/swiftlang/swift/issues/47929