How to force usage of protocol default extension "override"?

AirXygène

I have a protocol with PAT that provides a default implementation in an extension. Then, a class conforming that protocol provides an "override". This override is not called, and the compiler "prefers" the default.

//---- Definition of the protocol with a default implentation, because I am forced to.

protocol Bag: AnyObject {
    associatedtype BagObject
    
    func add(_ e: BagObject)
}

extension Bag where BagObject: Equatable {
    //    I here give a default implementation, because I can't do differently, as this
    //    is an extension, and it is an extension because it only applies to assoicated
    //    types that are Equatables
    func contains(_ e: BagObject) -> Bool { 
        print("Default implementation is called")
        return false 
    }
}

///---- Definition of a class that gives a concrete implementation of the protocol

class BagConcreteImplementation<BagObject>: Bag {
    var bag = Array<BagObject>()
    func add(_ e: BagObject) { bag.append(e) }
}

extension BagConcreteImplementation where BagObject: Equatable {
    //    I here give a concrete implementation when the generic type is Equatable
    func contains(_ e: BagObject) -> Bool { 
        print("Concrete implementation is called")
        return bag.contains(e) 
    }
}



///---- This is a class that encapsulate a bag, in real life, this class is adding some filtering to objects that can be added to the bag

class AClassThatHaveABag<BagType: Bag> {
    typealias BagObject = BagType.BagObject
    
    let myBag: BagType
    init(bag: BagType) { myBag = bag }
}

extension AClassThatHaveABag where BagType.BagObject: Equatable {
    func contains(_ e: BagObject) {
        //    The problem here is that the compiler only knows that myBag is a Bag
        // of Int and therefore calls the default implementation
        //    It does not call the concrete implementation of the concrete class that WILL be provided
        myBag.contains(e)
    }
}



let aBagOfInt    = BagConcreteImplementation<Int>()
let objectThatContainsABagOfInt = AClassThatHaveABag(bag: aBagOfInt)

aBagOfInt.contains(0)
objectThatContainsABagOfInt.contains(0)

// Prints
// Concrete implementation is called
// Default implementation is called

We can clearly see the direct call is call the concrete implementation, while the encapsulated call is calling the default implementation.

How to do to make sure the concrete implementation is always called, even through an encapsulation ?

Sweeper

I tried a few things, and somehow this works:

Declare contains in the protocol, not in an extension, like this:

func contains<T>(_ e: T) -> Bool where T: Equatable, T == BagObject

If you do things like T == BagObject in a class, a compiler error will show up saying that this makes T redundant, but apparently this is okay in a protocol.

Then, implement the default implementation like this:

extension Bag {
    func contains<T>(_ e: T) -> Bool where T: Equatable, T == BagObject {
        print("Default implementation is called")
        return false
    }
}

Then, you can just implement the concrete implementation directly in the class, as a non-generic method.

class BagConcreteImplementation<BagObject> : Bag {
    func contains(_ e: BagObject) -> Bool where BagObject : Equatable {
        print("Concrete implementation is called")
        return bag.contains(e)
    }
    
    var bag = Array<BagObject>()
    func add(_ e: BagObject) { bag.append(e) }
}

Without changing the call site, the code would print:

Concrete implementation is called
Concrete implementation is called

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

override protocol extension default implementation

How to override a protocol extension's default implementation of a func?

How to override computed property of protocol extension in Swift

How to override instance method from protocol extension in Swift?

Implementing a concrete type's property override of its protocol extension default in array of metatypes

How to add default implementation using generic protocol extension?

How to invoke protocol extension default implementation with type constraints

AudioKit MIDIListener force me to override its protocol

Swift: Providing a default protocol implementation in a protocol extension

Extension of protocol with method which adds default parameter

Default implementation of protocol extension in Swift not working

Why extension allows to override the default Double method?

How to Override a default method?

How to enforce usage of the @Override annotation?

How to define initializers in a protocol extension?

How to implement the CustomStringConvertible for a protocol in extension?

Swift: Why is the default protocol implementation used when an override is in place?

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

How to override the default sorting of Hadoop

How to override default Grails environment?

How to override default titlefont in quarto?

How will pandas override the default delimiter

how to override default values of a provisioner?

How to override default Polymer CSS

Wagtail: How to override default ImageEmbedHandler?

How to override the default method in CanCanCan

How to override SSH default identity?

How to force wireshark to show protocol names?

How to force SMB2 protocol in samba?