Keywords: Swift | open keyword | access control
Abstract: This article provides an in-depth exploration of the open access level introduced in Swift 3, detailing its distinctions from the public keyword and explaining its specific meanings for classes and class members. Through practical code examples from the ObjectiveC.swift standard library, it illustrates application scenarios. Based on Swift Evolution Proposal SE-0117, the article explains how open separates accessibility from overridability outside the defining module, offering Swift developers a clear understanding of the access control model.
Evolution of Swift's Access Control Model
Prior to Swift 3, the access control model primarily included three levels: private, internal, and public. However, as Swift gained widespread adoption in modular development, the original public access level presented a significant semantic ambiguity: it simultaneously indicated both accessibility and overridability outside the module, which could lead to unnecessary restrictions or unexpected behavior overrides in certain design scenarios.
Introduction and Design Philosophy of the open Keyword
Swift 3 introduced the open access level through SE-0117 proposal, titled "Allow distinguishing between public access and public overridability." The core objective of this change was to clearly separate accessibility from overridability outside the module, providing framework and library designers with finer-grained control capabilities.
As Swift language creator Chris Lattner noted in related discussions: "open is now simply 'more public than public,' providing a very simple and clean model." This statement accurately captures the design intent of open—it adds a new dimension to access control while maintaining backward compatibility.
Detailed Comparison Between open and public
The key to understanding the open keyword lies in systematically comparing it with public:
- Class-level distinction: An
openclass is both accessible and subclassable outside the defining module, whereas apublicclass is only accessible but not subclassable outside the defining module. - Class member-level distinction: An
openclass member is both accessible and overridable outside the defining module, while apublicclass member is only accessible but not overridable outside the defining module.
This distinction has significant practical implications. Consider the following code example:
// Defined in a framework module
open class BaseViewController {
open func viewDidLoad() {
// Base implementation
}
public final func setupLayout() {
// Layout setup, not allowed to override
}
}
// Used in an application module
class CustomViewController: BaseViewController {
override open func viewDidLoad() {
super.viewDidLoad()
// Custom implementation
}
// Error: Cannot override setupLayout as it's public and final
// override func setupLayout() { }
}
In this example, open allows the viewDidLoad method to be overridden in subclasses, while public combined with final ensures the implementation stability of the setupLayout method.
Practical Application in ObjectiveC.swift
Returning to the specific example from the question, the ObjectiveC.swift file from the Swift standard library contains the following code:
extension NSObject : Equatable, Hashable {
/// ...
open var hashValue: Int {
return hash
}
}
The open var hashValue declaration here has specific implications:
NSObjectis an Objective-C bridging class serving as the foundation for many Swift classes- The
hashValueproperty is marked asopen, meaning it is both accessible and overridable in subclasses ofNSObject - This design allows subclasses to provide custom hash implementations while maintaining type system integrity
Consider the following override example:
class CustomObject: NSObject {
let identifier: String
init(identifier: String) {
self.identifier = identifier
super.init()
}
override open var hashValue: Int {
return identifier.hashValue
}
}
In this custom class, we provide specialized hash computation based on the identifier property, which is precisely what the open access level permits.
Migration Considerations and Best Practices
For projects migrating from earlier Swift versions, note the following changes:
- In Swift versions before Swift 3, the behavior now provided by
openwas previously offered bypublic - Existing
publicdeclarations may need adjustment toopenwhen migrating to Swift 3, depending on design intent - Framework designers should carefully consider which APIs truly require the
openaccess level
Best practice recommendations:
- Use
publicby default, reservingopenonly when subclassing or overriding is explicitly needed - For APIs that should not be overridden, use
publicor combine it with thefinalmodifier - In framework design, use
opencautiously to avoid unexpected behavior changes
Conclusion
The introduction of the open keyword represents a mature evolution of Swift's access control model. By clearly separating accessibility from overridability, it provides finer-grained control mechanisms for large codebases and framework development. Understanding the distinction between open and public not only aids in correctly using existing APIs but also guides developers in designing more robust and maintainable Swift code. As the Swift language continues to evolve, this modularity-focused access control design will remain crucial.