Absence of "virtual" keyword and consequences in swift.
Hello everyone. Because there is no "virtual" keyword I don't know that how can I create a subclass which has 2 methods with 2 rule for each one:
First method:
Second method:
Let me explain with c# code
// <BEGIN_IMPORTANT_PART>
Console.WriteLine("From base_derived");
Base base_derived = new Derived();
base_derived.ifPolyCallBase(); // nonOverridedFromBase
base_derived.ifPolyCallDerived(); // overridedFromDerived
// <END_IMPORTANT_PART>
Console.WriteLine("\nFrom base");
Base @base = new Base();
@base.ifPolyCallBase(); // nonOverridedFromBase
@base.ifPolyCallDerived(); // overridedFromBase
Console.WriteLine("\nFrom derived");
Derived derived = new Derived();
derived.ifPolyCallBase(); // nonOverridedFromDerived
derived.ifPolyCallDerived(); // overridedFromDerived
class Base
{
virtual public void ifPolyCallBase()
{
Console.WriteLine("nonOverridedFromBase");
}
virtual public void ifPolyCallDerived()
{
Console.WriteLine("overridedFromBase");
}
}
class Derived : Base
{
public void ifPolyCallBase()
{
Console.WriteLine("nonOverridedFromDerived");
}
override public void ifPolyCallDerived()
{
Console.WriteLine("overridedFromDerived");
}
}
In swift when i use override it calls only derived method, we cannot use without override too, and i cannot delete the method too because of other functionalities as you see. So my questions are:
Thanks!
With closest swift code I tried to explain what I want. Is there any way to change first output without change other ones.
class Base {
func ifPolyCallBase() {
print("FromBase")
}
func ifPolyCallDerived() {
print("FromBase")
}
}
class Derived: Base {
override func ifPolyCallBase() {
print("FromDerived")
}
override func ifPolyCallDerived() {
print("FromDerived")
}
}
let base_derived: Base = Derived()
base_derived.ifPolyCallBase() // FromDerived (PROBLEM: But I want to see output "FromBase" without change other outputs)
base_derived.ifPolyCallDerived() // FromDerived
let base: Base = Base()
base.ifPolyCallBase() // FromBase
base.ifPolyCallDerived() // FromBase
let derived: Derived = Derived()
derived.ifPolyCallBase() // FromDerived
derived.ifPolyCallDerived() // FromDerived
In Swift, as in many languages which support inheritance, methods defined on classes are always dynamically-dispatched (virtual
); Swift does not have functionality which allows you to differentiate between whether a method was called on Derived
while its static type was Derived
or Base
.
However, Swift does offer static dispatch in two ways, which may help you achieve what you're after:
static
methods, defined at the type level and not on instances, are always statically-dispatched. If you define a static
method on your Base
class which takes an instance of Base
, you can centralize the definition and decide what to do with an instance there:
class Base {
static func ƒ(with instance: Base) { … }
}
class Derived: Base {}
Base.ƒ(with: Base())
Dervied.ƒ(with: Derived())
There is a downside to this approach, though: static
methods cannot be overridden by subclasses. This means that you can get b: Base = Base()
and b: Base = Derived()
behavior, but not d: Derived = Derived()
behavior — because you will only ever be calling the Base
method
There is one incidental alternative that does allow you to implement what you describe more directly: methods defined in extensions to protocols (but which are not protocol requirements, defined in the original protocol definition itself) are also always statically-dispatched. If you take the Base
method, define its implementation on a marker protocol, and conform Base
to it, you can get the method to statically-dispatch when called on Base
:
protocol P {}
extension P {
// This method _must_ be defined in an extension, and not exist in the
// declaration of `P` or else it will by dynamically-dispatched.
func ƒ() {
print("Base")
}
}
class Base: P {} /* "inherit" `P.ƒ()` */
class Derived: Base {
func ƒ() {
print("Derived")
}
}
Base().ƒ() // => "Base"
Derived().ƒ() // => "Derived"
(Derived() as Base).ƒ() // => "Base"
It's important to note that the reason this works is that P.ƒ()
and Derived.ƒ()
are two entirely separate methods, which just happen to have the same name, but based on context, static dispatch picks one or the other. Derived.ƒ()
does not override P.ƒ()
— it just happens to be called with the same name. This does have the consequence that Derived.ƒ()
is dynamically dispatched: if you need multiple layers of inheritance (e.g., DerivedDerived
), this approach on its own will not be sufficient.