1

Can we have default values for method's arguments on protocol extensions?

If so can we override those methods on structs that implement that protocol?

I'm doing it, but I'm having unexpected results. Why is that? Thanks!

import Foundation

protocol Datasource {
    func getLetter(_ uppercased: Bool) -> String
}

extension Datasource {

    func getLetter(_ uppercased: Bool = true) -> String {
        return uppercased ? "B" : "b"
    }
}

struct ADatasource: Datasource {

    func getLetter(_ uppercased: Bool = true) -> String {
        return uppercased ? "A" : "a"
    }
}

let datasource: Datasource = ADatasource()
datasource.getLetter(true) // returns "A"
datasource.getLetter()     // returns "B"   
offcourse
  • 326
  • 3
  • 12
  • 2
    Possible duplicate of [Implementing a function with a default parameter defined in a protocol](https://stackoverflow.com/q/42634816/2976878) – Hamish Jan 29 '19 at 18:12

2 Answers2

1

Honestly, not sure why .getLetter() opts for the protocol extension over the overwritten implementation.

However, I do know a good workaround which will achieve what you're trying to do:

protocol Datasource {
    func getLetter(_ uppercased: Bool) -> String
}

extension Datasource {

    func getLetter() -> String {
        return getLetter(true)
    }

    func getLetter(_ uppercased: Bool) -> String {
        return uppercased ? "B" : "b"
    }
}

struct ADatasource: Datasource {

    func getLetter(_ uppercased: Bool) -> String {
        return uppercased ? "A" : "a"
    }
}

let datasource: Datasource = ADatasource()
datasource.getLetter(true) // returns "A"
datasource.getLetter()     // now returns "A"
XmasRights
  • 1,427
  • 13
  • 21
1

If I recall correctly, this is because of dynamic dispatch vs static dispatch. Methods declared in protocol extensions are not dispatched dynamically.

Since the method without an explicit argument is not defined in the protocol, the call is dispatched statically. And since you've defined datasource as type Datasource, the implementation of the protocol is called instead of the implementation of ADatasource.

If you remove the explicit type and just use let datasource = ADatasource(), it will work as expected.

Rengers
  • 14,911
  • 1
  • 36
  • 54