Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift protocol and extension, I need to call overridden method or default extension method as per requirement

I have a protocol Vehicle and its extension like below:

protocol Vehicle {
    func Drive()    
}

extension Vehicle {
    func Stop() {
        print("iiiich...")
    }
}

And I also have declaration like below for Stop Method

struct Car: Vehicle {
    func Drive() {
        print("Can Drive")
    }
    func Stop() {
        print("yo stop")
    }
}

let myCar = Car()
myCar.Drive()
myCar.Stop()

But its override the Stop Method

// Output
// Can Drive
// yo stop

And as per my requirement I need default method sometime and some time overridden method definition

like image 735
Pankaj Bhardwaj Avatar asked Aug 07 '18 07:08

Pankaj Bhardwaj


3 Answers

Hey I got the answers that is to conform the protocol by the object call your default method rather than overriddedn, so we can call both defination as required

let honda: Vehicle = Car()
honda.Drive()
honda.Stop()
// Output
// Can Drive
// iiiich..

When we create a variable without type then this is static dispatch when a object conform a protocol only.

like image 66
Pankaj Bhardwaj Avatar answered Nov 16 '22 01:11

Pankaj Bhardwaj


If you need the method declared in the protocol extension, just make the compiler think that the car is of type Vehicle:

let myCar = Car()
(myCar as Vehicle).Stop()
like image 41
Sweeper Avatar answered Nov 16 '22 00:11

Sweeper


As already mentioned in the answers, the generic solution is to make sure that the instance that calls Stop() method is of type Vehicle (not Car). Nevertheless I would mention what's the logic behind it.

Personally, I think that there is a possibility to face this issue when it comes to work with the POP paradigm. Protocol extensions is a handy way the apply Polymorphism in our code, however it does leads to this "weird" behavior!

Static Dispatch:

Firstly, keep in mind that it is not a bug. In case of:

let honda: Vehicle = Car()
honda.Drive()
honda.Stop()

there is a manual cast to the honda as Vehicle, at this point the compiler will use static dispatch, which means that it would be recognizable which method should be called (Vehicle().Stop or Car().Stop) during the compile time. It selects the default implementation for Vehicle which is implemented in the extension, without the need of checking what is the concrete type.

Dynamic Dispatch:

In case of:

let myCar = Car()
myCar.Drive()
myCar.Stop()

nothing special goes here, it works exactly as expected. That's exactly the the meaning of dynamic dispatch, which leads to apply polymorphic operations during the run time.

To make it more clear, consider that you have another type that conforms to Vehicle protocol:

struct Bus: Vehicle {
    func Drive() {
        print("Bus Drive")
    }
    func Stop() {
        print("Bus stop")
    }
}

let myBus = Bus()
myCar.Drive()
myCar.Stop()

Obviously, the print("Bus stop") is the one which will be called, and actually that's the expected! The compiler is "smart" enough to recognize which method to be selected based on what is the concrete type (Bus().Stop).

Furthermore:

For better understanding of what's going on here, reviewing Understanding Swift Performance Apple session might be helpful.

like image 37
Ahmad F Avatar answered Nov 16 '22 00:11

Ahmad F