2

Suppose there is the following protocol with a default implementation of someFuncWithDefaultImplementation() provided by an extension.

Then is it possible for MyClass2 to both provide its own implementation of someFuncWithDefaultImplementation() which also invokes the default implementation of that method from the extension?

protocol MyProtocol : class {
    func someFuncWithDefaultImplementation()
    func someFunc()
    var  someInt:Int { get set }
}

extension MyProtocol {
    func someFuncWithDefaultImplementation() {
        someInt = 5
    }

    func someFunc() {
        someFuncWithDefaultImplementation()
    }
}

class MyClass :  MyProtocol {
    var someInt = 6
}

class MyClass2 : MyProtocol
{
    var someInt: Int = 4
    func someFuncWithDefaultImplementation()
    {
        // do some additional stuff
         /*** someFuncWithDefaultImplementation()  invoke MyProtocol extension implementation here ***/
    }
}


    let class1 = MyClass()
    class1.someFunc()

    let class2 = MyClass2()
    class2.someFunc()
Gruntcakes
  • 37,738
  • 44
  • 184
  • 378
  • 1
    Possible duplicate of [Calling protocol default implementation from regular method](http://stackoverflow.com/questions/32602712/calling-protocol-default-implementation-from-regular-method) – TylerP Apr 11 '17 at 19:17
  • 2
    @MrSaturn - tried the solution in your duplicate, it does not appear to work in this case. – Gruntcakes Apr 11 '17 at 19:24
  • @TusharSharma don't understand your comment. Where is there an extension which is overriding existing functionality in the code? There is one extension which is providing a default implementation, where is it overriding functionality? – Gruntcakes Apr 11 '17 at 19:26
  • 1
    Make sure to look at [the (non-elegant) answer using a nested dummy type](http://stackoverflow.com/a/32606899/4573247) in the linked dupe thread (e.g., `class Dummy : MyProtocol { var someInt: Int = 0 }` and `Dummy().someFuncWithDefaultImplementation()` in the body of `someFuncWithDefaultImplementation()` of `MyClass2` above). – dfrib Apr 11 '17 at 19:26
  • i think it . use override keyword before method – Nazmul Hasan Apr 11 '17 at 19:27
  • @SausageNinja Interesting, I guess that doesn't work anymore. I'll retract my close vote. – TylerP Apr 11 '17 at 19:35
  • @Nazmul Hasan. Before what method? Anyway, there is nothing to actually override, a protocol is not a class. – Gruntcakes Apr 11 '17 at 19:38
  • 1
    OP: again, look at the thread linked to by MrSaturn, specifically about the nested dummy type. Also, don't care about everyone speaking about overriding as they mistake protocols default implementations vs. provided in conformance to subclassing. – dfrib Apr 11 '17 at 19:38
  • http://stackoverflow.com/questions/35686636/swift-inherited-protocol-method-override – Nazmul Hasan Apr 11 '17 at 19:40
  • @dfri - the accepted answer doesn't work. I'll check out the other answer. – Gruntcakes Apr 11 '17 at 19:46
  • @SausageNinja note that I explicitly linked, in my first comment, to an answer other than the accepted one. – dfrib Apr 11 '17 at 19:47
  • @dfri, was using MrSaturn's link to the same question, thus didn't notice your link jumped to the other answer. – Gruntcakes Apr 11 '17 at 19:49
  • I don't believe the other answer will work in this case either, as you'll be interacting with the dummy's `someInt` – not `MyClass2`s (although you could probably do some trickery with closures in order to make it work). – Hamish Apr 11 '17 at 19:49
  • @Hamish indeed, it will make use the default implementation but for the concrete `Dummy` type (only after your comment do I realize that OP might want to make use of `Class2`:s `someOne` within the call to the default implementation). – dfrib Apr 11 '17 at 19:55
  • it will work using the dummy (though in my case, due to the protocol being a class protocol, its even more inelegant. – Gruntcakes Apr 11 '17 at 20:00
  • @Hamish and with some trickery... :D – dfrib Apr 11 '17 at 20:18

2 Answers2

1

The following answer in the thread

describes using a nested dummy type to access the default implementation of a protocol from within a type that already has supplied its own implementation of that blueprinted method. We may extend this method to also allow actually making use of (blueprinted) properties of the MyClass2 instance, but within the call to the default implementation which MyClass2 already implements its custom version of (hence taking precedence over the default one).

We start by looking at a slightly more light weight version of your example, with a default implementation supplied for someFuncWithDefaultImplementation()

protocol MyProtocol : class {
    func someFuncWithDefaultImplementation()
    var someInt: Int { get set }
}

extension MyProtocol {
    func someFuncWithDefaultImplementation() {
        print("Called default impl. Currently, someInt = \(someInt)")
        print("Mutates someInt from within default implementation (0) ...")
        someInt = 0
    }
}

We use the non-elegant nested type solution in the custom implementation of someFuncWithDefaultImplementation() of MyClass2, to call the default implementation of the latter, but stores a reference in the Dummy instance back to the MyClass2 instance, to allow the someInt property of MyClass2 to be used in the default implementation call (for reading and writing), even if this is called from the Dummy type.

class MyClass2 : MyProtocol
{
    var someInt: Int = 42

    func someFuncWithDefaultImplementation()
    {
        // do some additional stuff ...
        print("In MyClass2 implementation, currently someInt = \(someInt)")

        /* Dummy 'MyClass2'-capturing type used to call the default
            implementation of 'MyProtocol', but with read and write 
            access to 'MyClass2':s self:s 'someInt' instance. */
        class Dummy : MyProtocol {
            unowned let myClass2: MyClass2
            init(_ myClass2: MyClass2) { self.myClass2 = myClass2 }
            var someInt: Int {
                get { return myClass2.someInt }
                set { myClass2.someInt = newValue }
            }
        }

        // call default implementation of 'someFuncWithDefaultImplementation'
        // supplying 'self' to read/write access to self.someInt.
        Dummy(self).someFuncWithDefaultImplementation()

        print("Back in MyClass2:s implementation; now someInt = \(someInt)") 
           // 0, woah, mutated in default implementation!
    }
}

let a = MyClass2()
a.someFuncWithDefaultImplementation()
/* In MyClass2 implementation, currently someInt = 42
   Called default impl. Currently, someInt = 42
   Mutates someInt from within default implementation (0) ...
   Back in MyClass2:s implementation; now someInt = 0         */

You could also choose to declare the nested Dummy outside of the function, just marking it private to make sure it cannot be accessed from outside MyClass2:

class MyClass2 : MyProtocol
{
    var someInt: Int = 42

    /* Dummy 'MyClass2'-capturing type used to call the default
       implementation of 'MyProtocol', but with read and write 
       access to 'MyClass2':s self:s 'someInt' instance. */
    private class Dummy : MyProtocol {
        unowned let myClass2: MyClass2
        init(_ myClass2: MyClass2) { self.myClass2 = myClass2 }
        var someInt: Int {
            get { return myClass2.someInt }
            set { myClass2.someInt = newValue }
        }
    }

    func someFuncWithDefaultImplementation()
    {
        // do some additional stuff ...
        print("In MyClass2 implementation, currently someInt = \(someInt)")

        // call default implementation of 'someFuncWithDefaultImplementation'
        // supplying 'self' to read/write access to self.someInt.
        Dummy(self).someFuncWithDefaultImplementation()

        print("Back in MyClass2:s implementation; now someInt = \(someInt)") 
           // 0, woah, mutated in default implementation!
    }
}

I will, however, repeat the same as the author of the linked answer: this approach is not very elegant.

Community
  • 1
  • 1
dfrib
  • 70,367
  • 12
  • 127
  • 192
  • Yeah, I was going down the same path, [but using closures instead](https://gist.github.com/hamishknight/4b583505527d91008f4fc75a5683d5fe) :) I still can't help but feel like there must be an easier way though – although really protocol default implementations aren't meant to be "super" implementations, only alternative implementations. It's possible that in OP's actual use case, this may be better done with inheritance (but impossible to say for sure without seeing a concrete example). – Hamish Apr 11 '17 at 20:39
  • @Hamish I believe, as you say, that default implementations are generally not meant to be used in this context, hence the (likely; feel free to ping me if you find an easier way) lack easy ways to accomplish this. Neat with the closures and putting the work on protocol level (`MyProtocol`) rather than in a single type (as I've done above) that wants to make use of this somewhat exotic feature. Now late @ .se, night! – dfrib Apr 11 '17 at 20:46
  • I mean, an obvious simpler way would be to just create another method in the extension for the default implementation, and have the extension's `someFuncWithDefaultImplementation` chain to it – then to call the default implementation, just call the method with the default implementation :) But yeah, apart from that – I can't think of another way that doesn't involve *some* dummy type (including a dummy 'super'-protocol). – Hamish Apr 11 '17 at 21:58
-1

Only if you subclass as well, see in:

import Foundation

protocol MyProtocol : class {
    func someFuncWithDefaultImplementation()
    func someFunc()
    var  someInt:Int { get set }
}

extension MyProtocol {
    func someFuncWithDefaultImplementation() {
        someInt = 5
        print("a")
    }

    func someFunc() {
        someFuncWithDefaultImplementation()
    }
}

class MyClass :  MyProtocol {
    var someInt = 6
}

class BaseClass: MyProtocol {
    var someInt: Int = 4
}
class MyClass2 : BaseClass
{

    func someFuncWithDefaultImplementation()
    {
        // do some additional stuff
        print("b")
        (self as BaseClass).someFuncWithDefaultImplementation()
    }
}

If you add the above in a Playground and then call:

MyClass2().someFuncWithDefaultImplementation()

It prints:

b
a

Which is what you are asking for, see screenshot.

enter image description here

Andre
  • 1,135
  • 9
  • 20
  • This doesn't work. When MyClass2 inherits from MyProtocol then its implementation of someFuncWithDefaultImplementation() gets called as intended. However if it changes to inherit from MyClass then that is no longer the case - the protocol extension implementation gets called directly. – Gruntcakes Apr 11 '17 at 19:35
  • 1
    That's strange, works in latest Xcode 8.3.1 Playground (as shown in the screenshot) – Andre Apr 11 '17 at 19:39
  • 1
    Have you tried invoking it as in the question i.e. MyClass2().someFunc() – Gruntcakes Apr 11 '17 at 19:40
  • The problem with this is that it won't use (protocol) dynamic dispatch – `MyClass2`'s implementation of `someFuncWithDefaultImplementation()` won't be called from a context where the compiler doesn't know that the instance is a `MyClass2` (e.g `(MyClass2() as BaseClass).someFuncWithDefaultImplementation()`). This is because [subclasses don't get to directly re-implement protocol requirements](http://stackoverflow.com/a/42286148/2976878). – Hamish Apr 11 '17 at 19:43
  • True, I'm mistaken: my solution won't solve the problem calling someFunc(), I got tricked by the question title. Sorry – Andre Apr 11 '17 at 19:45
  • @André. Thanks for having a go anyway. – Gruntcakes Apr 11 '17 at 19:47