Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Swift, why subclass method cannot override the one, provided by protocol extension in superclass

I know the title of this question is confusing but the weird behaviour is explained in the example below:

protocol Protocol {
    func method() -> String
}

extension Protocol {
    func method() -> String {
        return "From Base"
    }
}

class SuperClass: Protocol {
}

class SubClass: SuperClass {
    func method() -> String {
        return "From Class2"
    }
}

let c1: Protocol = SuperClass()
c1.method() // "From Base"
let c2: Protocol = SubClass()
c2.method() // "From Base"

How come c1.method() and c2.method() return the same? How come the method() in SubClass doesn't work?

Interestingly, without declaring the type of c2, this is going to work:

let c2  = SubClass()
c2.method() // "From Class2"
like image 444
aquajach Avatar asked Oct 07 '15 14:10

aquajach


People also ask

Can we override function in extension in Swift?

If a protocol defines a method, and provides a default implementation in an extension, a class can override that method, and the override will be called for any reference to the instance, even if the reference's type is declared as the protocol.

Can we override method in extension?

Extension methods cannot be overridden the way classes and instance methods are. They are overridden by a slight trick in how the compiler selects which extension method to use by using "closeness" of the method to the caller via namespaces.

Can we override class method in Swift?

Classes in Swift can call and access methods, properties, and subscripts belonging to their superclass and can provide their own overriding versions of those methods, properties, and subscripts to refine or modify their behavior.


1 Answers

The problem is that c1 and c2 are of type Protocol, as you've defined their type explicitly this way (remember: protocols are fully fledged types). This means, when calling method(), Swift calls Protocol.method.


If you define something like:

let c3 = SuperClass()

...c3 is of type SuperClass. As SuperClass has no more specific method() declaration, Protocol.method() is still used, when calling c3.method().


If you define something like:

let c4 = SubClass()

...c4 is of type SubClass. As SubClass does have a more specific method() declaration, SubClass.method() is used, when calling c4.method().


You could also get c2 to call SubClass.method(), by down-casting it to `SubClass:

(c2 as! SubClass).method() // returns "From Class2"

Here's a demonstration on SwiftStub.

like image 95
Marcus Rossel Avatar answered Nov 15 '22 08:11

Marcus Rossel