← thecodex.expert · The Codex Family of Knowledge
Swift

Access Control

public lets code in another module use your class — but subclassing or overriding it from outside that module genuinely requires the separate, stronger open level.

Swift 6 open ≠ public — a real distinction Last verified:
Canonical Definition

internal is the default access level when nothing is specified — visible throughout the defining module, but not beyond it. fileprivate restricts visibility to the same source file; private restricts it further, to the same enclosing declaration (and, since Swift 4, extensions of that type in the same file). public makes something usable from another module, but NOT subclassable or overridable there; open is a genuinely separate, stronger level specifically permitting subclassing and overriding across module boundaries — a distinction most languages with public/private access control don't make at all, since they conflate "can use" and "can extend" into one level.

The five levels, from most to least restrictive

Without any modifier at all, internal is what's actually in effect — code anywhere else in the SAME module can use this class freely, but nothing outside that module can see it at all.

Swiftaccess_levels.swift
private class Secret { }        // same enclosing declaration/file only
fileprivate class FileHelper { }   // same source file only
class DefaultInternal { }          // no modifier — internal by default, module-wide
public class PublicAPI { }         // usable from other modules
open class ExtendableAPI { }        // usable AND subclassable from other modules

open vs public: the real, distinctive difference

A framework author marking a class public but not open is making a deliberate statement: use this class freely, but don't subclass it — a genuinely useful constraint public alone can't express, since it only controls usage, not extension.

Swiftopen_vs_public.swift
// In a framework module:
public class Logger {
    public func log(_ message: String) { print(message) }
}

open class Plugin {
    open func execute() { }
}

// In a DIFFERENT module that imports this framework:
let logger = Logger()            // fine — public allows usage
// class MyLogger: Logger { }    // COMPILE ERROR: Logger is public, NOT open — can't subclass

class MyPlugin: Plugin {         // fine — Plugin is open, subclassing across modules is allowed
    override func execute() { }
}

private and fileprivate: fine-grained same-file control

Since Swift 4, private is also visible to extensions of the SAME type within the same file — letting a type's implementation be split across an extension for organization, without needing the broader fileprivate.

Swiftprivate_scope.swift
class BankAccount {
    private var balance: Double = 0   // visible only within BankAccount itself (and its extensions)
}

extension BankAccount {
    func deposit(_ amount: Double) {
        balance += amount   // fine — same-file extension can see 'private' since Swift 4
    }
}

Sources

1
Apple / Swift.org. The Swift Programming Language, "Access Control," docs.swift.org/swift-book.