- Proposal: SE-TBD
- Author(s): Olivier Halligon, Caleb Davenport, Brian King, Erica Sadun
- Status: tbd
- Review manager: tbd
This proposal enhances protocol safety at compile time by incorporating role keywords to discourage two categories of potential user errors. This proposal can be phased in first over time and language release.
This proposal was first discussed on the Swift Evolution list in the [Pitch] Requiring proactive overrides for default protocol implementations. thread. This version has been modified to limit scope and application, with type-implementation impact moved to a possible second proposal.
Protocol extensions can either satisfy a required member to provide a default implementation, or introduce extended functionality.
Consider this protocol and extension, which compiles successfully yet contains three potential errors
protocol ExampleProtocol {
func thud(with value: Float64)
}
extension ExampleProtocol {
// 1: Near-miss type
func thud(with value: Double) { ... }
// 2: Near-miss name
func thus(with value: Float64) { ... }
// 3: Accidental satisfaction, intended as extra method
func thud(with value: Float64) { ... }
}
Errors 1 and 2 represent near-miss implementations. The first uses the wrong parameter type (Double
). The second misnames the method (thus
). Neither error satisfies the protocol requirement with a default implementation as intended.
Error 3 represents an accidental default implementation. Possibly implemented in a separate file, away from the protocol declaration, the coder intends to adds an extra method and accidentally satisfies a protocol requirement.
A further error occurs when a coder updates a protocol member name:
protocol ExampleProtocol {
func thump(with value: Float64) // formerly thud
}
extension ExampleProtocol {
// 4: Orphaned default implementation after rename
func thud(with value: Float64) { ... }
}
Error 4 represents an implementation where the intended protocol default implementation no longer satisfies the protocol requirement. Renaming a method in the protocol and forgetting to rename the default implementation can lead to hard-to-spot bugs and hidden behavior changes instead of a clear error.
The compiler does not pick up on or respond to any of these mismatches between coder intent and protocol code.
This proposal introduces two optional keywords, nominally called default
and extend
(although this can be bikeshedded) to eliminate these error classes. Under this system, coders can annotate their protocols to ensure compile-time detection of these problems.
extension ExampleProtocol {
// Error: Does not satisfy any known protocol requirement
// Fixit: replace type with Float64
public default func thud(with value: Double) { ... }
// Error: Does not satisfy any known protocol requirement
// Fixit: replace name with `thud`
// (Using nearest match already implemented in compiler)
public default func thus(with value: Float64) { ... }
// Error: Name overlaps with existing protocol requirement
// Fixit: replace `extend` keyword with `default`
// Fixit: rename function signature with `thud_rename_me`
// and `FIXME:` annotation
public extend func thud(with value: Float64) { ... }
}
// Demonstrating updated member name in the protocol, which
// has changed from `thud` to `thump`.
extension ExampleProtocol {
// Error: Does not satisfy any known protocol requirement
// Fixit: replace `extend` keyword with `default`
public extend func thud(with value: Float64) { ... }
}
Note: Swift cannot provide a better fixit under this proposal for the final error. Swift does not provide an annotation mechanism for previous API decisions. That kind of annotation approach (presumably implemented through documentation markup) is out of scope for this proposal.
As optional "best practices", these changes do not affect existing Swift code. It should be easy for a migrator pass to offer to introduce the keywords to enhance code safety.
-
This proposal does not make role keywords mandatory. Swift would be safer if role annotation were required in extensions, either with
default
orextend
or equivalent bikeshedded terms. -
The Swift compiler can generate warnings for methods in protocol extensions that are not annotated, with a proper Fixit.
-
This proposal addresses errors in protocol extensions (near misses and accidental default implementations). A similar proposal could address similar errors in type implementations.
Not at this time.
Thanks, Doug Gregor, Jordan Rose, and Joe Groff