Swift: How to Add a Protocol Extension to a Protocol

Swift: Is it possible to add a protocol extension to a protocol?

It seems there are two use-cases of why you may want to do what you are doing. In the first use-case, Swift will allow you to do what you want, but not very cleanly in the second use-case. I'm guessing you fall into the second category, but I'll go through both.

Extending the functionality of TheirPcol

One reason why you might want to do this is simply to give extra functionality to TheirPcol. Just like the compiler error says, you cannot extend Swift protocols to conform to other protocols. However, you can simply extend TheirPcol.

extension TheirPcol {
func extraFunc() { /* do magic */ }
}

Here, you are giving all objects that conform to TheirPcol the method extraFunc() and giving it a default implementation. This accomplishes the task of extending functionality for the objects conforming to TheirPcol, and if you want it to apply to your own objects as well then you could conform your objects to TheirPcol. In many situations, however, you want to keep MyPcol as your primary protocol and just treat TheirPcol as conforming to MyPcol. Unfortunately, Swift does not currently support protocol extensions declaring conformance to other protocols.

Using TheirPcol objects as if they were MyPcol

In the use case (most likely your use case) where you really do need the separate existence of MyPcol, then as far as I am aware there is no clean way to do what you want yet. Here's a few working but non-ideal solutions:

Wrapper around TheirPcol

One potentially messy approach would be to have a struct or class like the following:

struct TheirPcolWrapper<T: TheirPcol>: MyPcol {
var object: T

func extraFunc() { /* Do magic using object */ }
}

You could theoretically use this struct as an alternative to casting, as in your example, when you need to make an existing object instance conform to MyPcol. Or, if you have functions that accept MyPcol as a generic parameter, you could create equivalent functions that take in TheirPcol, then convert it to TheirPcolWrapper and send it off to the other function taking in MyPcol.

Another thing to note is if you are being passed an object of TheirPcol, then you won't be able to create a TheirPcolWrapper instance without first casting it down to an explicit type. This is due to some generics limitations of Swift. So, an object like this could be an alternative:

struct TheirPcolWrapper: MyPcol {
var object: MyPcol

func extraFunc() { /* Do magic using object */ }
}

This would mean you could create a TheirPcolWrapper instance without knowing the explicit type of the TheirPcol you are given.

For a large project, though, both of these could get messy really fast.

Extending individual objects using a child protocol

Yet another non-ideal solution is to extend each object that you know conforms to TheirPcol and that you know you wish to support. For example, suppose you know that ObjectA and ObjectB conform to TheirPcol. You could create a child protocol of MyPcol and then explicitly declare conformance for both objects, as below:

protocol BridgedToMyPcol: TheirPcol, MyPcol {}

extension BridgedToMyPcol {
func extraFunc() {
// Do magic here, given that the object is guaranteed to conform to TheirPcol
}
}

extension ObjectA: BridgedToMyPcol {}
extension ObjectB: BridgedToMyPcol {}

Unfortunately, this approach breaks down if there are a large number of objects that you wish to support, or if you cannot know ahead of time what the objects will be. It also becomes a problem when you don't know the explicit type of a TheirPcol you are given, although you can use type(of:) to get a metatype.

A note about Swift 4

You should check out Conditional conformances, a proposal accepted for inclusion in Swift 4. Specifically, this proposal outlines the ability to have the following extension:

extension Array: Equatable where Element: Equatable {
static func ==(lhs: Array<Element>, rhs: Array<Element>) -> Bool { ... }
}

While this is not quite what you are asking, at the bottom you'll find "Alternatives considered", which has a sub-section called "Extending protocols to conform to protocols", which is much more what you're trying to do. It provides the following example:

extension Collection: Equatable where Iterator.Element: Equatable {
static func ==(lhs: Self, rhs: Self) -> Bool {
// ...
}
}

Then states the following:

This protocol extension would make any Collection of Equatable elements Equatable, which is a powerful feature that could be put to good use. Introducing conditional conformances for protocol extensions would exacerbate the problem of overlapping conformances, because it would be unreasonable to say that the existence of the above protocol extension means that no type that conforms to Collection could declare its own conformance to Equatable, conditional or otherwise.

While I realize you're not asking for the ability to have conditional conformances, this is the closest thing I could find regarding discussion of protocols being extended to conform to other protocols.

how to extend a swift protocol with an extension so that classes get an implemented variable defined by the protocol

Currently your protocol defines isSharable as { get set }

protocol Sharable {
func share(name: String)
var isSharable: Bool { get set }
}

This means that when you construct your extension it is not actually conforming to the protocol

extension Sharable where Self: User {
func share(name: String) { print(name) }
var isSharable: Bool { return !name.isEmpty }
}

This is due to the fact that you have defined isSharable in your extension as a computed property. Computed properties are get only.

You can make your extension conform to the Sharable protocol by removing the set requirement. So your protocol would become:

protocol Sharable {
func share(name: String)
var isSharable: Bool { get }
}

Make a protocol conform to another protocol

Protocols can inherit each other:

Protocol Inheritance


A protocol can inherit one or more other protocols and can add further requirements on top of the requirements it inherits. The syntax for protocol inheritance is similar to the syntax for class inheritance, but with the option to list multiple inherited protocols, separated by commas:

protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
// protocol definition goes here
}

So, you basically need to do this:

protocol InstrumentForProfessional {
var title: String {get}
}

protocol Pen: InstrumentForProfessional {
var title: String {get} // You can even drop this requirement, because it's already required by `InstrumentForProfessional`
var color: UIColor {get}
}

Now everything that conforms to Pen conforms to InstrumentForProfessional too.

How does protocol extension work in Swift?

I don't think there is even a need to inherit from NSObject if you are making a BaseClass to be inherited by other classes.

You can simply add classTag in the BaseClass itself, i.e.

class BaseClass {
var classTag: String {
return String(describing: type(of: self))
}
}

class SubClass: BaseClass {
func someFunc() {
print(self.classTag)
}
}

Another option can be to use protocol and protocol extension and provide the default definition of classTag, i.e.

protocol SomeProtocol {
var classTag: String { get }
}

extension SomeProtocol {
var classTag: String {
return String(describing: type(of: self))
}
}

Then, you can conform SomeProtocol to the classes wherever required, i.e.

class SubClass: SomeProtocol {
func someFunc() {
print(self.classTag)
}
}

In any case, inheriting from NSObject is unnecessary since you don't need any NSObject specific functionality for that.

Swift protocol extension in Objective-C class

Objective-C protocols cannot have default implementations.

Objective-C protocols can have real optional methods/properties, unlike Swift protocols, which only have required methods/properties. The workaround for this in Swift is the use of a default implementation, however, sadly those cannot be seen in Objective-C.

I would suggest creating a pure Swift protocol and for all Objective-C classes that want to extend this, write the conformance in Swift, then create @objc wrapper functions in Swift that call the default protocol implementations - if it needs to be called, if it doesn't need to be called, simply ignore it.

Something along the lines of:

protocol SwiftProtocol {
func requiredFunc()
func optionalFunc()
}

extension SwiftProtocol {
func optionalFunc() {}
}

@objc extension ObjcClass: SwiftProtocol {
@objc func requiredFunc() {
print("do something")
}

// This will call the default implementation - can be omitted if you don't need to call the default implementation from Objective-C
@objc func objc_optionalFunc() {
optionalFunc()
}
}

Swift protocol and extension, I need to call overridden method or default extension method as per requirement

Hey I got the answers that is to conform the protocol by the object call your default method rather than overriddedn, so we can call both defination as required

let honda: Vehicle = Car()
honda.Drive()
honda.Stop()
// Output
// Can Drive
// iiiich..

When we create a variable without type then this is static dispatch when a object conform a protocol only.

Extentions for more than one protocol at once

In general, it is not possible to write a single extension on multiple protocols. This would require the compiler to figure out the set intersection of all the members in all those protocols (those are the members you have access to in the extensions), which the compiler cannot do.

To avoid code duplication, you would need to work out the members that you need - in your case init(integerLiteral:) and <=, put those in your own protocol, and make the concrete types you want the extension to apply to, conform to your own protocol:

// inheriting from Comparable and ExpressibleByIntegerLiteral gives you the members you need
protocol BinaryNumbers : Comparable & ExpressibleByIntegerLiteral {

}

extension BinaryNumbers {
func atMost127() -> Bool {
self <= 127
}
}

extension Int: BinaryNumbers {}
extension Int8: BinaryNumbers {}
extension Int16: BinaryNumbers {}
extension Int32: BinaryNumbers {}
extension Int64: BinaryNumbers {}
// ... plus the unsigned versions, if you need them

extension Float16: BinaryNumbers {}
extension Float32: BinaryNumbers {}
extension Float64: BinaryNumbers {}
extension Float80: BinaryNumbers {}

Now you might ask, why don't we just make an extension of Comparable & ExpressibleByIntegerLiteral then, as they provide all the members we are using? Well, because that's not a nominal type, and you can't write extensions on non-nominal types :(

However, you could write it in this way:

// now you don't need your own "BinaryNumbers"!
extension Comparable where Self: ExpressibleByIntegerLiteral {
func atMost127() -> Bool {
self <= 127
}
}

You are only able to do this because the two members you need all came from protocols. If for some reason you need a member that both BinaryFloatingPoint and BinaryInteger has, but isn't provided by any of the protocols they conform to, then you need to write your own protocol with those members, and manually conform everything to that protocol.



Related Topics



Leave a reply



Submit