Skip to content

Instantly share code, notes, and snippets.

@zats
Last active December 25, 2015 04:52
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 zats/52476a83627f5e4c0a85 to your computer and use it in GitHub Desktop.
Save zats/52476a83627f5e4c0a85 to your computer and use it in GitHub Desktop.
Allow additional inheritance in protocol extensions

Allow additional inheritance in protocol extensions

Introduction

Currently, protocol extension does not allow adding inheritance clauses even if extension implements all the functions.

Motivation

Certain cases of protocol extensions make protocol A effectively to conform to a protocol B, however currently there is no way to mark it as such. Consider following example:

protocol Serializable {
    init?(data: NSData)
    var data: NSData? { get }
}

protocol JSONSerializable {
    init?(json: [String: AnyObject])    
    var jsonValue: [String: AnyObject] { get }
}

Essentially, JSONSerializable can be conform to Serializable through following extension:

extension JSONSerializable: Serializable {
    init?(data: NSData) {
        guard let rawJson = try? NSJSONSerialization.JSONObjectWithData(data, options: []),
            json = rawJson as? [String: AnyObject] else {
                return nil
        }
        self.init(json: json)
    }
    
    var data: NSData? {
        return try? NSJSONSerialization.dataWithJSONObject(jsonValue, options: [])
    }
}

However, currently, there is no way of stating that JSONSerializable conforms to Serializable, code above wont compile producing following error message: "Extension to protocol JSONSerializable cannot have an inheritance clause".

Proposed solution

Allow add inheritance clauses to protocol extensions as long as all required functions. Compiler should still produce an error if protocol extension is marked as conforming to a protocol but not all functions or properties implemented.

Alternatives considered

Currently it is possible to achieve the same effect either by declaring protocol A inheriting from the protocol B and implementing parent methods in the extension like so:

public protocol JSONSerializable: Serializable {
    init?(json: [String: AnyObject])
    
    var jsonValue: [String: AnyObject] { get }
}

extension JSONSerializable {
    init?(data: NSData) {
        guard let rawJson = try? NSJSONSerialization.JSONObjectWithData(data, options: []),
            json = rawJson as? [String: AnyObject] else {
                return nil
        }
        self.init(json: json)
    }
    
    var data: NSData? {
        return try? NSJSONSerialization.dataWithJSONObject(jsonValue, options: [])
    }
}

or by declaring a child protocol C, inheriting from both JSONSerializable and Serializable and implementing requirements in the extension like in the example above.

While first solution is not always possible if the protocol is not declared in your codebase, the second solution introduces a different semantics making it unacceptable for certain cases, and, simply, looks less elegant.

Impact on existing code

There is no impact on existing code.

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