Skip to content

Comment on Why Java folks should stop looking down on C#: differences in similaritiesparent

Comments

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 :-)

AboutSource Built by g1lg1l

Hackerly is an independent reader for Hacker News, built on the public HN API. Not affiliated with Y Combinator.