Calling Protocol Default Implementation from Regular Method

Calling protocol default implementation from regular method

I don't know if you are still looking for an answer to this, but the way to do it is to remove the function from the protocol definition, cast your object to Foo and then call the method on it:

protocol Foo { 
// func testPrint() <- comment this out or remove it
}

extension Foo {
func testPrint() {
print("Protocol extension call")
}
}

struct Bar: Foo {
func testPrint() {
print("Call from struct")
(self as Foo).testPrint() // <- cast to Foo and you'll get the default
// function defined in the extension
}
}

Bar().testPrint()

// Output: "Call from struct"
// "Protocol extension call"

For some reason it only works if the function isn't declared as part of the protocol, but is defined in an extension to the protocol. Go figure. But it does work.

Call protocol default implementation in inherence tree

Although protocols support concrete implementations using extension but that defies the concept of a protocol

A protocol defines a blueprint of methods, properties, and other
requirements that suit a particular task or piece of functionality.

and it should be avoided as much as possible until you are truly sure this will not be overriden.

Solution 1:

If you have been into a situation mentioned then i would suggest to introduce an intermediary class that does nothing except conforming to that protocol and then inherit subClasses from that class.

public class Intermediary: MyProtocol {}

public class MyFirstClass: Intermediary {
public func sayCheese() {
print("Cheese from 1")

super.sayCheese()
}
}

public class MySecondClass: MyFirstClass {
override init() {
super.init()

sayHi()
}

public func sayHi() {
print("Hi from 2")
super.sayHi()
}

public override func sayCheese() {
print("Said cheese from 2")
super.sayCheese()
}
}

Now creating object MySecondClass() will print the below output,

Hi from 2
Hi, I am protocol
Cheese from protocol

Solution 2:

As mentioned in the other question, remove sayCheese method from the protocol so your protocol declaration will be empty but sayCheese will stay in the extension and it will break the recursive calls to sayCheese allowing your app to not freeze.

public protocol MyProtocol {}

How the call the default implementation code in protocol in swift?

A protocol is more like a compile-time guarantee that type has certain methods and properties. Default implementation adds another layer of complexity to this by injecting an implementation to the protocol's adopters. I don't have the skills to go through Swift's source code but I think when the adopter provide its own implementation, the default implementation is overshadowed and there's no way to get it back.

A workaround is to add a method with a different name to your protocol, which provides the default implementation and can be called by any adopter:

protocol ImplementedProtocol {
func printInfo()

func defaultPrintInfo()
}

extension ImplementedProtocol where Self: BaseClass {
func printInfo() {
defaultPrintInfo()
}

func defaultPrintInfo() {
print("Hello! This is ImplementedProtocol")
}
}

class SuperClass: BaseClass, ImplementedProtocol {
func printInfo() {
self.defaultPrintInfo()
print("Hello! This is SuperClass")
}
}

Swift: calling default implementation of protocol func from custom implementation

Simply remove the declaration from the protocol and only have the extension definition. Then, the compiler will only use the extension method if the concrete type doesn't have an override or if it doesn't know anything about the concrete type except that it conforms to Foo

protocol Foo {
// Declaration was deleted
}

extension Foo {
func bar() {
print("bar form extension")
}
}

enum Day: Foo {
case sunday, monday

func bar() {
switch self {
case .sunday: print("bar custom implementation")
case .monday: (self as Foo).bar()
}
}
}

Day.sunday.bar() // prints "bar custom implementation"
Day.monday.bar() // prints "bar form extension"

You need (self as Foo) to make the compiler forget that self is a Day and fall back on the Foo extension function.

Swift protocol extension method is called instead of method implemented in subclass

This is just how protocols currently dispatch methods.

A protocol witness table (see this WWDC talk for more info) is used in order to dynamically dispatch to implementations of protocol requirements upon being called on a protocol-typed instance. All it is, is really just a listing of the function implementations to call for each requirement of the protocol for a given conforming type.

Each type that states its conformance to a protocol gets its own protocol witness table. You'll note that I said "states its conformance", and not just "conforms to". BaseClass gets its own protocol witness table for conformance to MyProtocol. However SubClass does not get its own table for conformance to MyProtocol – instead, it simply relies on BaseClass's. If you moved the
: MyProtocol down to the definition of SubClass, it would get to have its own PWT.

So all we have to think about here is what the PWT for BaseClass looks like. Well, it doesn't provide an implementation for either of the protocol requirements methodA() or methodB() – so it relies on the implementations in the protocol extension. What this means is that the PWT for BaseClass conforming to MyProtocol just contains mappings to the extension methods.

So, when the extension methodB() method is called, and makes the call out to methodA(), it dynamically dispatches that call through the PWT (as it's being called on a protocol-typed instance; namely self). So when this happens with a SubClass instance, we're going through BaseClass's PWT. So we end up calling the extension implementation of methodA(), regardless of the fact that SubClass provides an implementation of it.

Now let's consider the PWT of JustClass. It provides an implementation of methodA(), therefore its PWT for conformance to MyProtocol has that implementation as the mapping for methodA(), as well as the extension implementation for methodB(). So when methodA() is dynamically dispatched via its PWT, we end up in its implementation.

As I say in this Q&A, this behaviour of subclasses not getting their own PWTs for protocols that their superclass(es) conform to is indeed somewhat surprising, and has been filed as a bug. The reasoning behind it, as Swift team member Jordan Rose says in the comments of the bug report, is

[...] The subclass does not get to provide new members to satisfy the conformance. This is important because a protocol can be added to a base class in one module and a subclass created in another module.

Therefore if this was the behaviour, already-compiled subclasses would lack any PWTs from superclass conformances that were added after the fact in another module, which would be problematic.


As others have already said, one solution in this case is to have BaseClass provide its own implementation of methodA(). This method will now be in BaseClass's PWT, rather than the extension method.

Although of course, because we're dealing with classes here, it won't just be BaseClass's implementation of the method that's listed – instead it will be a thunk that then dynamically dispatches through the class' vtable (the mechanism by which classes achieve polymorphism). Therefore for a SubClass instance, we'll wind up calling its override of methodA().

Override of protocol default implementation in a subsubclass doesn't participate in dynamic dispatch

Thee are several rules involved here.

Sometimes Static Dispatch is used (in this case we must look at the type of the var/let to find out the implementation that will be used).

Other times Dynamic Dispatch is used instead (this means the implementation of the object inside the variable is used).

Let's consider the general example

let foo: SomeType1 = SomeType2()
foo.f()

I'll use the following definitions

  • classic implementation of f() to indicate when f() is defined outside of a protocol extension (so inside a struct/class).

  • default implementation of f() to indicate when f() is defined inside a protocol extension.

Dynamic Dispatch

If SomeType1 is a struct/class with it's own "classic" implementation of f() then polymorphism is applied.

It means that if SomeType2 doesn't have a classic implementation of f() then SomeType1.f() is used. Otherwise SomeType2.f() wins.

Static Dispatch

If SomeType1 doesn't have a classic implementation of f() but has a default implementation, then polymorphism is turned off.

In this case default implementation of the type of the let/var wins.

a.

Let's look at your first example

let a: A = C()
a.f() // "AAAA"

In this A doesn't have it's own classic implementation (because it's not a struct/class) but has a default implementation. So polymorphism is turned off and A.f() is used.

b.

Same rule for your second example

let b: B = C()
b.f() // "AAAA"

B doesn't have classic implementation of f(), but has a default implementation of f(). So polymorphism is turned off and B.f() (from the protocol extension) is used.

c.

Finally the object of type C is inside a constant of type C.

var c:C
c.f() // "CCCC"

Here C has a classic implementation of f(). In this case the protocol implementation is ignored and C.f() is used.

More

Let's see another example

protocol Alpha { }
extension Alpha { func f() -> String { return "Alpha"} }
protocol Beta { }
extension Beta { func f() -> String { return "Beta"} }

class Foo: Alpha, Beta { }

let alpha: Alpha = Foo()
alpha.f() // "Alpha"

let beta: Beta = Foo()
beta.f() // "Beta"

As you can see, again, the type of the constant containing the value wins. And if you put the Foo object inside a Foo constant you get a compile error

let foo: Foo = Foo()
foo.f() //

error: ambiguous use of 'f()'
foo.f()
^
Swift 2.playground:2:23: note: found this candidate
extension Beta { func f() -> String { return "Beta"} }
^
Swift 2.playground:6:24: note: found this candidate
extension Alpha { func f() -> String { return "Alpha"} }

Swift protocol default values are not changable

var type1: AssetViewAttribures = Crypto(name: "name", logo: URL(string: "https://pixabay.com/de/illustrations/online-maus-web-internet-weltweit-523234/")!, symbol: "symbol", avgPrice: "123", precision: 2)

type1.avgPrice

This would call the getter declared in the protocol extension, which just returns "". This is because Crypto.avgPrice has no relation to the avgPrice declared in the protocol extension. You can't "override" a member in an extension, because extensions are dispatched statically. The compiler sees that test is of type AssetViewAttributes, finds the default getter you have declared in the extension, and that's what it will call.

To fix this, you need to add avgPrice as a requirement of the protocol:

protocol AssetViewAttributes {
...
var avgPrice: String { get }
}

This causes Swift to find avgPrice declared in the protocol, and dispatches it dynamically. If the implementing class happens to implement avgPrice, that implementation will be called. If not, then the default implementation is called.

Calling a protocol extension initializer

An init within a protocol is required, and therefore has to be implemented explicitly i.e. a default implementation cannot be utilised.

As for 'explicitly calling a protocol extension's initializer', you cannot instantiate a protocol type.

I would suggest using inheritance for this.

Can a method be overridden by protocol default implementation?

From what I recall from WWDC video, if a class provides an implementation for a method that also has a protocol default implementation, the one from the class wins. I.e. the protocol's implementation is only used when the class does not provide one.

IMO, if that would be other way around (or if there would be another way to override class implementation by a protocol implementation), that would open some nasty doors. E.g. suddenly standard framework functionality working differently because of that.

At any rate, why would you want to override existing class method(s) by protocol default implementation?



Related Topics



Leave a reply



Submit