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

You're not the only person in that position. I'm a developer from the Java camp and moved over to the C# camp (by work necessity, Oracle, etc); and, of all the features of C# that I enjoy (Properties, Attributes, Lambda expressions, etc.) I absolutely abhor the idea that I, as a developer, have to know, perfectly, what future subclasses are going to want/need to run properly. It has never made sense and always felt like it was taking away one of the core tenants of object orientation (though I know that neither Java nor C# are true-OO languages). I know it probably technically doesn't, but that's how I've felt ever since I heard about doing it "another way"



As a library developer, you can explicitly declare all your methods as overridable. The key point is that in large scale software development, in Java, you can have the following undesirable situation:

Version 1, you import a third party library:

    public class ThirdParty
    {
        public void calculateAndPrintResult()
        {
            System.out.println("1");
        }
    }

    public class Mine extends ThirdParty
    {
        public void calculateAndPrintResult()
        {
            super.calculateAndPrintResult();
            this.printResult();
        }

        protected void printResult()
        {
            System.out.println("2");
        }

        public static void main(String[] arguments)
        {
            Mine mine = new Mine();
            mine.calculateAndPrintResult();
            // Prints 1, 2
        }
    }
Version 2, third party has refactored and introduced printResult. You swap in the new third party library and suddenly the behavior has changed:

    public class ThirdParty
    {
        public void calculateAndPrintResult()
        {
            this.printResult();
        }

        protected void printResult()
        {
            System.out.println("1");
        }
    }

    public class Mine extends ThirdParty
    {
        public void calculateAndPrintResult()
        {
            super.calculateAndPrintResult();
            this.printResult();
        }

        protected void printResult()
        {
            System.out.println("2");
        }

        public static void main(String[] arguments)
        {
            Mine mine = new Mine();
            mine.calculateAndPrintResult();
            // Prints 2 ! (wrong)
        }
    }
While this example is trivial, bear in mind, when you have programming in the large, i.e. large codebases with a lot of third party libraries and many teams of developers, you would rather not have surprises like this pulled on you, or you pulling surprises like this on other people.

It can take a lot of work tracking down this kind of bug.

When you finally realize this type of issue arises despite everyone following "best practice" OOP, then the reason is because "best practice" OOP is not actually best practice.


It prints "2%n2", where %n is the platform-specific newline; but that's not really important, as your point is still made.

I can see how that would become a problem, a potentially terrible problem, but for a situation like that, wouldn't private methods solve that problem?

I can see more complex situations with this, but at some point, and they'd be annoying to break down. I don't throw out my position on this, though, as good documentation could help at least a few cases of this. Also, newer versions of Netbeans encourage the use of the @Override attribute, to help ensure things like this down happen, I imagine (I don't actually know what the @Override attribute is for, as I've only used it in large Java projects where I was the only developer).


> wouldn't private methods solve that problem?

Not if the third party developer intends to override it in his own subclasses.

Documentation may solve the issue, but this goes against the "just works" philosophy.

The root of the problem is versioning. Your class was developed against version 1 of the base class. You expect further changes in implementation of the base class should not materially affect your running code.

To achieve this, one of the sacrifices is the all methods are not overridable by default (i.e. not virtual), but instead have to be explicitly declared virtual AND the subclass has to explicitly state they wish to override the base class.


Why is it reasonable or desirable for a programmer to expect that switching to a new version of a library should have no effect on dependent code?


the problem runs deeper. When version 2 of the ThirdParty class ships, suddenly your class doesn't work. If another team has subclassed your class and overridden your printResult routine, you are effectively stuck. You can't take in bug fixes that exists in version 2 and the other team effectively couldn't move forward either. Remember, this is best practice OO, and there really hasn't been any changes to the interface. So effectively this is like version 1.01.

It is namespace pollution of a very subtle and devious kind.


@Override is typically used to detect when you intend to override some method of the superclass but mistakenly don't. Such as when you misspell a method or something. By default the 1.6 compiler will treat it as optional and the situation described above is possible. However, you can tell the compiler to treat a missing @Override as an error which would give you an indication of the problem above.

edit: unless you misspell the method you intend to override and forget to include the annotation, in which case the compiler can't help you :-)


As a long-time Java developer, I absolutely abhor the assumption that everything can be safely subclassed and overridden unless it is explicitly declared as final.

Implementation inheritance breaks encapsulation. It creates an intimate entanglement between the internal implementation details of the super- and sub-classes. Every time you extend a class or override a method that wasn't explicitly and carefully designed to be subclassed and overridden safely, you are _writing hacky code_.

There are, of course, places for hacky code. If you understand why something is hacky and feel it's a worthwhile trade-off then by all means you should be able to do it. Java, though, encourages people to pepper their code with such hacks before they have learned why they shouldn't.


s/tenants/tenets/




Consider applying for YC's Spring batch! Applications are open till Feb 11.

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

Search: