Skip to content

Instantly share code, notes, and snippets.

@AliSoftware
Last active June 5, 2017 00:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AliSoftware/ec4cdc8fb312b264729de01e36c9b55b to your computer and use it in GitHub Desktop.
Save AliSoftware/ec4cdc8fb312b264729de01e36c9b55b to your computer and use it in GitHub Desktop.
Introducing Role Keywords to Protocol Implementations

Introducing Role Keywords to Protocol Implementations to Reduce Code Errors

Introduction

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.

Motivation

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.

Proposed Solution

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.

Impact on Existing Code

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.

Alternatives and Future Directions

  • This proposal does not make role keywords mandatory. Swift would be safer if role annotation were required in extensions, either with default or extend 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.

Alternatives Considered

Not at this time.

Acknowledgements and Thanks

Thanks, Doug Gregor, Jordan Rose, and Joe Groff

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment