Hacker News new | past | comments | ask | show | jobs | submit login

It's sufficient, in that it does what you want - it calls save() on b's A.

But it's not sufficient if what you want is to treat a B as an A. There is no is-a, so you have to keep treating a B as something different from an A.




This becomes difficult to discuss in the abstract. In my experience, save() is a clear example of exactly why you want composition and not inheritance. When I am saving the B record, I want it to let the A record's save do its thing without interfering. Let's for the sake of argument use Person and Employee instead of A and B so we can use a concrete example. We'll say Person has a name field and an address field. Employee owns a Person, and has an EmployeeID as well as Salary. You want:

    Employee : Person
    {
        string employeeID;
        double salary;
    }
I want:

    Employee
    {
        Person person;
        string employeeID;
        double salary;
    }
If we're saving into JSON, your save contents are mixing with the Person's save contents ("{name, address, salary, employeeID}"). What happens when a "basic income" law is passed, and all of a sudden the Person's implementor decides to add a salary field to the Person object? My method continues working without hiccup, because I was explicit about how I saved:

    save()
    {
     write("{ employeeid:whatever, salary:whatever, person: ");
     save(person);
     write("}");
    }
My save file displays the same encapsulation as my code, and thus behaves correctly when a base class changes by default. On the other hand, in subclass-land you'd now have competing salary fields, so you'd have to explicitly prepare for that, instead of getting it semantically for free. For example, you could start defensively programming by name-spacing the save properties: "{person-name, person-address, person-salary, employee-salary, employee-employeeID}".

In my experience this reliance on what "things are" is a bad way to think about programming. It doesn't help anyone to argue the philosophy of whether Employee is a Person or not, because I can easily sidestep the argument by saying: "OK fine, Employees are Persons... but I'm not longer writing the Employee class, I'm writing the EmployeeRecord class. And as such the person instance itself is part of the employee set if it has an associated EmployeeRecord. I have now satisfied the is-a relationship without an is-a language feature". Kind of like how certain Rectangle ARE squares regardless of whether they happen to be members of the Square class. Its a membership requirement, not an instantiation requirement. Its just words.




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: