Last active
January 29, 2016 20:47
-
-
Save koleson/6782d9d05931f1a06f2f to your computer and use it in GitHub Desktop.
Confusion: Method overrides in extensions
This file contains hidden or 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
// Playground - unexpected extension method selection | |
import Foundation | |
var str = "Hello, playground" | |
protocol MethodProtocol { | |
func aMethod() -> String | |
} | |
class Base : NSObject { | |
required override init() { | |
// nothing, but we must have this intializer to init from a .Type object | |
} | |
func aMethod() -> String { | |
return "called the base aMethod" | |
} | |
func anotherMethod() -> String { | |
return "called the base anotherMethod" | |
} | |
} | |
class Subclass : Base { | |
// we'll override aMethod in the extension | |
override func anotherMethod() -> String { | |
return "called the subclass anotherMethod" | |
} | |
} | |
extension Subclass { | |
override func aMethod() -> String { | |
return "called the subclass aMethod" | |
} | |
} | |
var arrayOfClasses = Array<Base.Type>() | |
arrayOfClasses.append(Subclass.self) | |
var baseObj = Base() | |
baseObj.aMethod() // returns "called the base method" - expected | |
var subclassObj = Subclass() | |
subclassObj.aMethod() // returns "called the subclass method" - expected | |
var subclassType = Subclass.self | |
var subclassObjInstantiatedFromType = subclassType.init() | |
subclassObjInstantiatedFromType.aMethod() // returns "called the subclass method" - expected | |
var subclassObjInstantiatedFromArrayType = arrayOfClasses[0].init() // inferred type: Base | |
let dynamicTypeOfObjInstantiatedFromArrayType = subclassObjInstantiatedFromArrayType.dynamicType // returns Subclass.Type - expected | |
subclassObjInstantiatedFromArrayType.aMethod() // returns "called the base method" - wat? | |
subclassObjInstantiatedFromArrayType.anotherMethod() // returns "called the subclass anotherMethod" - better, but... wat? | |
if let subclassObjAsSubclass = subclassObjInstantiatedFromArrayType as? Subclass { | |
subclassObjAsSubclass.aMethod() // returns "called the subclass method" - expected | |
} | |
// so clearly the inferred type of the variable impacts method dispatch. but how do we | |
// dynamically type the variable based on the object's concrete type? | |
// we want to avoid any references to the concrete type at compile-time. | |
// the "if let ... as? ..." construct requires a compile-time type, so it won't work. | |
// this illustrates the problem more succinctly, the above is just a contrived | |
// example of what we can see here. | |
var subclassObjAsBase: Base = Subclass() | |
subclassObjAsBase.aMethod() // returns "called the base aMethod" - hmm |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment