Last active
October 28, 2016 18:27
-
-
Save JoshuaSullivan/0752d008e1aa08febdd18c25954183d7 to your computer and use it in GitHub Desktop.
This playground demonstrates a potentially confusing gotcha when using protocols that have default method implementations along with class inheritance.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//: # Protocols and Inheritance | |
//: This playground demonstrates a gotcha in the use of protcols with default | |
//: method implementations along with class inheritance. | |
import UIKit | |
//: This protocol defines a single method that takes an `Int` and returns an `Int`. | |
protocol Doable { | |
func doSomething() -> Int | |
} | |
//: This extension provides a default implementation which simply returns 1. | |
extension Doable { | |
func doSomething() -> Int { | |
print("Default doSomething implementation called.") | |
return 1 | |
} | |
} | |
//: The `Base` class conforms to Queryable, but does not implement the | |
//: `doSomething(value:)` method, relying on the default implementation. | |
class Base: Doable { | |
} | |
//: The `Sub` class inherits from `Base` and adds its own implementation of the | |
//: `doSomething(value:)` protocol function. | |
class Sub: Base { | |
/// This custom impelmentation returns the stored itemCount. | |
func doSomething() -> Int { | |
print("Subclass implementation of doSomething() called.") | |
return 5 | |
} | |
} | |
//: Now, let's build a list of objects conforming to Queryable, including 1 `Base` instance. | |
var doList: [Doable] = [] | |
doList.append(Base()) | |
doList.append(Sub()) | |
doList.append(Base()) | |
doList.append(Base()) | |
doList.append(Base()) | |
//: You might expect this reduce call, which adds up the result of invoking `doSomething` | |
//: on each of the Queryable objects would return a result of 8. | |
let sum = doList.reduce(0, { (count, query) -> Int in | |
let itemCount = query.doSomething() | |
return count + itemCount | |
}) | |
//: However, we get 5, and you can see in the console that the print statement in the | |
//: `Sub` implementation of `doSomething` is never called. | |
print("Final sum: \(sum)") | |
//: This is because `Sub` does not conform to `Queryable`, `Base` does. When the resolver | |
//: checks if `Sub` has an implementation of `doSomething` and it does not, the resolver | |
//: uses the default implementation instead. | |
//: | |
//: In order to make this work as expected: | |
//: * Add the `doSomething` method to `Base` (it can just return 1). | |
//: * Change the signature of `doSomething` in `Sub` to include the `override` keyword. | |
//: | |
//: ### Try it out! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment