5

Is it possible to get the following code to make MyClass2:someFuncWithDefaultImplementation() invoked?

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 : MyClass
{
    func someFuncWithDefaultImplementation()
    {
        someInt = 7
    }
}


...

  let class2 = MyClass2()
  class2.someFunc()

MyClass2 could have this method added:

func someFunc() {
       someFuncWithDefaultImplementation()
}

And it would work, but that is no use if MyProtocol:someFunc() is doing other stuff apart from calling someFuncWithDefaultImplementation() as it would just be code duplication.

Also doing this does not have the desired effect:

extension MyClass2 {
    func someFuncWithDefaultImplementation()
    {
        someInt = 7
    }
}
Hamish
  • 78,605
  • 19
  • 187
  • 280
Gruntcakes
  • 37,738
  • 44
  • 184
  • 378
  • 1
    The thing is that classes have polymorphism (dynamic dispatch) and protocols do not. If we want polymorphic behavior, injecting an implementation of `someFuncWithDefaultImplementation` by way of a protocol extension is the wrong thing to do. — To put it another way: notice that you do not have to say `override` in order to implement `someFuncWithDefaultImplementation` in Class2. That tells you that it is not subject to polymorphism. – matt Apr 06 '17 at 00:28
  • To put it yet another way: the way to get polymorphism is to inject your implementation into the topmost _class_ that adopts MyProtocol. This could be in the original declaration or, if the class is not yours, through an extension _to the class_. – matt Apr 06 '17 at 00:42
  • Compare point #2 of [my answer here](http://stackoverflow.com/a/42286148/2976878) – subclasses cannot directly re-implement protocol requirements. – Hamish Apr 06 '17 at 07:10

1 Answers1

6

The default implementations in the protocols are only called if the class that conforms to these protocols do not implement that method itself. The classes' methods override the default implementations of the protocols, not the other way around.

you could do like this:

import UIKit

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()
    {
        someInt = 7
    }

}


let class2 = MyClass2()
class2.someFunc()

or like this:

class MyClass :  MyProtocol {
    var someInt = 6
    func someFuncWithDefaultImplementation() {
        someInt = 8
    }
}

class MyClass2 : MyClass
{
    override func someFuncWithDefaultImplementation()
    {
        someInt = 7
    }
}

these were what i got with my tests, but you may find some better solution

nsleche
  • 108
  • 1
  • 7
  • 2
    The first one doesn't relate to the original problem at all, because MyClass2 doesn't inherit from MyClass. The second one is exactly what I was saying in my comment: the fact that you have to say `override` tells you that polymorphism is now operative. As I said in my second comment, "the way to get polymorphism is to inject your implementation into the topmost _class_ that adopts MyProtocol". That's exactly what you've done in your second approach. – matt Apr 06 '17 at 01:47
  • @matt why they decided to introduce this confusing behaviour? I now can't supply default implementation directly in my protocol because I can't reliably override it in classes! What a disaster... Why to introduce default implementation in protocols then? – m8labs Jan 07 '18 at 13:18