# Subclassing an open Swift class is not always possible

In this blog post, I am elaborating on why defining an open class in Swift with only an internal designated initializer is pointless. I am looking particularly at the use case of subclassing that class outside its module.

# Designated Initializers vs. Convenience Initializers

**Designated** initializers are the primary initializers for a class. A designated initializer fully initializes all properties introduced by that class and calls an appropriate superclass initializer to continue the initialization process up the superclass chain.

**Every class must have at least one designated initializer.**

```swift
init(parameters) {
    statements
}
```

**Convenience** initializers are secondary, supporting initializers for a class. You can define a convenience initializer to call a designated initializer from the same class as the convenience initializer with some of the designated initializer’s parameters set to default values. You don’t have to provide convenience initializers if your class doesn’t require them. 

```swift
convenience init(parameters) {
    statements
}
```

# The Question

```Swift
// Module "Experiment"

open class Superclass {
    internal init(param1: String, param2: String) {}
    
    public convenience init(params: [String]) {
        self.init(param1: "", param2: "")
    }
}
```

Can `Superclass` be subclassed outside of its module?

# The short answer

No

# The explanation

At a first glance, it may look like it should be possible because the class has `open` access level.

> Open access applies only to classes and class members, which differs from public access by allowing code outside the module to subclass and override. Marking a class as open explicitly indicates that you’ve considered the impact of code from other modules using that class as a superclass and that you’ve designed your class’s code accordingly.

But the class has only a single designated initializer which has access level `internal`

> `internal` enables entities to be used within any source file from their defining module, but not in any source file outside of that module. You typically use internal access when defining an app’s or a framework’s internal structure.

Source: [Swift Language Guide - Access Control](https://docs.swift.org/swift-book/LanguageGuide/AccessControl.html)

So calling the designated initializer of the superclass will not work :(

```Swift
import Experiment

public class Subclass: Superclass {}

func test() {
    // ERROR: Subclass' cannot be constructed because it has no accessible initializers
    let subclass = Subclass(param1: "", param2: "")
}
```

What about calling the public convenience initializer from the superclass?

```Swift
import Experiment

public class Subclass: Superclass {}

func test() {
    // ERROR: Subclass' cannot be constructed because it has no accessible initializers
    let subclass = Subclass(params: [])
}
```

Nope :(

> Swift subclasses don’t inherit their superclass initializers by default.

> However, superclass initializers are automatically inherited if certain conditions are met.

> Rule 1: If your subclass doesn’t define any designated initializers, it automatically inherits all of its superclass designated initializers.

Rule 1 probably means it automatically inherits all the `public` and `open` superclass's designated initializers my example has none. 

> Rule 2: If your subclass provides an implementation of all of its superclass designated initializers—either by inheriting them as per rule 1, or by providing a custom implementation as part of its definition—then it automatically inherits all of the superclass convenience initializers.

Source: [Swift Language Guide - Initialization](https://docs.swift.org/swift-book/LanguageGuide/Initialization.html)

Rule 2 doesn't matter here as well. We cannot provide an implementation of the superclass's designated initializer because it's `internal`.

[Marina Gornostaeva](https://twitter.com/hybridcattt) asks the Swift team if the behavior is a bug or could be explained better through documentation. I am looking forward to their response.

%[https://twitter.com/hybridcattt/status/1578814941351407616]

What about adding a designated initializer in the subclass and calling the superclass's convenience initializer?

Not possible here because Swift requires that a designated initializer must call a designated initializer from its immediate superclass.

![initializerDelegation01_2x.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1665236568688/7GUQDxMyV.png align="left")

# Conclussion

Question: Can you subclass an `open` Swift class outside of its module if that class has a  single, `internal` designated initializer?
Answer: No

You should add a `public` designated initializer to your `open` class as a module developer.  Otherwise it is not possible to subclass it from outside of its module.

The alternative is to remove the `open` access level to make the intention clear that the class cannot be subclassed.


