What is the difference between public and open?

Both expose API across modules, but only open allows other modules to subclass a class or override its members

Answer

The core idea

Swift’s access control levels, from least restrictive to most restrictive:

  • open — usable from any module that imports the defining module, and subclassable / overridable from outside that module (classes and class members only)
  • public — usable from any module that imports the defining module, but not subclassable or overridable from outside
  • package — usable within the defining package, not outside it
  • internal — usable within the defining module (the default)
  • fileprivate — usable only in the defining source file
  • private — usable only in the enclosing declaration and same-file extensions of that declaration

public means “clients can use this.” open means “clients can use this, subclass it, and override its members.”

1. open

open is the highest access level. It applies only to classes and class members. Marking a class open means other modules may use it as a superclass. Marking a member open means those subclasses may override it. Per the language guide, choosing open is an explicit statement that the type was designed for that extension point.

swift 5.2
// Framework module
open class NetworkClient {
    public init() {}

    open func send() {
        // hook point for subclasses outside this module
    }

    public func reset() {
        // usable outside, but not overridable outside
    }
}

// App module
final class LoggingClient: NetworkClient { // ✅ open class
    override func send() { // ✅ open method
        print("logging")
        super.send()
    }

    // override func reset() {} // ❌ public method — not overridable from another module
}

A common framework pattern is an open class with a mix of open hook methods and public (or internal) helpers that stay under the author’s control.

2. public

public also exposes an entity to any module that imports the defining module. The difference is inheritance: other modules can use a public class and call its public members, but they cannot subclass the class or override those members.

These lines are intentionally wrong when LockedBase lives in a framework module and the subclasses are written in an app module:

swift 5.2
// Framework module
public class LockedBase {
    public init() {}
    public func configure() {}
}

// App module — importing the framework
let base = LockedBase() // ✅ can use the type
base.configure()        // ✅ can call the method

class CustomBase: LockedBase {} // ❌ cannot subclass a public class from another module

class AlternateClient: NetworkClient {
    override func send() {} // ❌ needs an open method to override across modules
}

Inside the defining module, public does not seal the type: you can still subclass a public class and override its visible members. The restriction is about other modules.

Why it matters

Subclassing across modules is an API contract. Swift keeps that opt-in via open (SE-0117) so frameworks can ship usable types without freezing every call path for unknown subclasses.

Interview angle

Start from the full ladder (openprivate), then zoom into the only difference that matters for this question: same visibility across modules, different inheritance rules. Mention that open is class-only, that same-module subclassing of public types still works, and that members must be marked open separately to be overridable outside. Primary reference: Access Control.