Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I'm reading J. Bloch's Effective Java and now I'm at inheritance vs composition section. As far as I understood he said that inheritance is not always good.

A related cause of fragility in subclasses is that their superclass can acquire new methods in subsequent releases. Suppose a program depends for its security on the fact that all elements inserted into some collection satisfy some predicate. This can be guaranteed by subclassing the collection and overriding each method capable of adding an element to ensure that the predicate is satisfied before adding the element. This works fine until a new method capable of inserting an element is added to the superclass in a subsequent release.

But why doesn't it work? The superclass is just the Collection interface and if we add a new method we just a compile-time error. That's not harmful ever...

share|improve this question
1  
Adding a new method to a super class doesn't cause such a compile-time error. In fact adding default methods to an interface doesn't produce a compile time error either. –  Peter Lawrey yesterday
    
If you are talking about java.util.Collection, that is NOT a super class. That is just an interface. –  Alderath yesterday
    
Adding an abstract method to super class or interface is compile time error if the sub-class is recompiled, but this might not happen. –  Peter Lawrey yesterday
1  
This is called the fragile base class problem. –  Seelenvirtuose yesterday

4 Answers 4

up vote 19 down vote accepted

Suppose you have a Collection superclass in some library v1.0:

public class MyCollection {
    public void add(String s) {
        // add to inner array
    }
}

You subclass it in order to only accept Strings that have length 5:

public class LimitedLengthCollection extends MyCollection {
    @Override
    public void add(String s) {
        if (s.length() == 5) {
            super.add(s);
        }
    }
}

The contract, the invariant of this class is that it will never contain a String that doesn't have length 5.

Now version 2.0 of the library is released, and you start using it. The base class is modified to:

public class MyCollection {
    public void add(String s) {
        // add to inner array
    }

    public void addMany(String[] s) {
        // iterate on each element and add it to inner array
    }
}

and your subclass is left unmodified. Now users of your subclass can do

LimitedLengthCollection c = new LimitedLengthCollection();
c.addMany(new String[] {"a", "b", "c"});

and the contract of your subclass is thus broken. It was supposed to only accept Strings of length 5, and it doesn't anymore, because an additional method has been added in the superclass.

share|improve this answer
    
Although this is to the heart of the problem (fragile base class), it only occurs if the addMany method does not use the add method but implements the adding behavior itself. Maybe you should add some implementation details to all those methods. –  Seelenvirtuose yesterday
1  
Correct. And that would cause another problem. Version 2.0 could delegate to add(), and you could rely on that to make the check only in add(), whereas version 3.0 would not delegate to add() anymore, and your check would thus be bypassed. –  JB Nizet yesterday
    
So, the point here is MyCollection is a concrete class. Got it. But in java 8, is implementing library's interfaces still safe? Their can provide default implementation for some methods and if we implement one of them at version 1.0 and at the version 2.0 some method is added with the default implementation we'll also probably get into trouble (as you pointed out to the broken invariant). –  St.Antario yesterday
    
@St.Antario interfaces indeed don't have this problem. –  JB Nizet yesterday
    
Even in Java 8 with the default implementation? –  St.Antario yesterday

The problem is not that inheritance could not work.

The problem is that with inheritance the developer can not enforce some behaviour (like the example of the collection that satisfy some predicate) .

When we create a new class rarely it really is a specialized type of another. More often it is something new that use other classes.

So rarely we need inheritance and more often we need to create a class that use other classes to so something.

The IS A vs HAS A

You have to ask yourself:

Class B IS A new sub type of Class A that do the same things of A in different ways ?

or

Class B HAS A class inside to do something different from what A is intented to do ?

And know that more often the right answer the latter.

share|improve this answer

if we add a new mehtod we just a compile-time error

That is true only when an abstract method is added to the superclass/interface. If a non-abstract method is added, it is perfectly valid not to override that new method.

share|improve this answer

Because it (in general) will break the client code that has implemented the Collection class.

In this particular example the security will be broken because malicious users would be able to insert items by using the non yet overridden method that was added after you have shipped your code.

Basing your code on inheriting classes you do not control may bite you in the future.

share|improve this answer
    
That would be a good thing in this case; if the client code breaks (fails to compile), then it will need to be fixed before it can be run, which means that the security threat is averted. –  RedRoboHood yesterday
    
Can you imagine Oracle altering the Collection class/interface at a latter point? What would be the issue with that? –  idipous yesterday
    
I don't disagree that altering a public interface like that would be a bad thing; I am simply pointing out that the question is about security concerns, in which case having code break would be preferable to causing a security problem. –  RedRoboHood yesterday
    
see my edit. If you have shipped your code then you have a security issue. –  idipous yesterday

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.