Search code examples
oopinheritancepolymorphismd

Why is this subclass' parent method call not polymorphic?


I've been dabbling in Dlang recently as C++ just wasn't quite sitting right with me after having used Python for so long. While dabbling, I came across what I thought would be a very simple exercise in polymorphism. I suppose how you would expect something to work and what it actually does are two entirely different things for reasons an end user probably can't comprehend. That being said, here is the source code of my "sandbox.D":

import std.stdio;

class Animal {
    string voice = "--silence--";
    void speak() {
        writeln(this.voice);
    }
}

class Dog : Animal {
    string voice = "Whoof!";
}

int main() {
    auto a = new Animal();
    auto d = new Dog();

    writeln(a.voice); // Prints "--silence--"
    writeln(d.voice); // Prints "Whoof!"

    a.speak(); // Prints "--silence--"
    d.speak(); // Prints "--silence--" NOT "Whoof!"

    return 0;
}

I guess my issue is why the "this" keyword just doesn't seem to be functioning how you would expect it to in the C++ successor language.


Solution

  • Methods are polymorphic, variables aren't. So instead of making the voice a variable, you want to override speak in the child.

    Also, the auto return type doesn't work with polymorphism, you need to actually specify the types. (The reason is that auto return makes a function template in the compiler, which in theory could have multiple overridable slots in the function table, so it just doesn't try to put it in.)

    So try this out:

    import std.stdio;
    
    class Animal {
      void speak() { // changed to void instead of auto
        writeln("--silence--");
      }
    }
    
    class Dog : Animal {
      override void speak() { // the override tells it to override the base method
        writeln("woof");
      }
    }
    
    int main() {
        auto d = new Dog();
        d.speak();
        return 0;
    }
    

    If you have a lot of shared functionality and want to reuse one function with slight changes in child classes, you might make a method instead of a variable that just returns something.

    Like string voice() { return "woof"; }, then it can be overridden in children.