User:Mordomo/FBC

=Fragile base class=

A fragile base class is a problem that occurs in object-oriented programming languages when a base class changes and unexpectedly affects its subclasses due to inheritance and self-recursion.

Causes
The problem is subtle and exists due to interaction between the class and its sub-classes rather than being a problem within the classes themselves. It is best illustrated by example: say a test to assert correctness exists for the base class and that the base class passes the test. Now, say a change is made to the base class. The base class continues to pass the test after the change. In addition, say a similar test exists for the sub-class, which also passes its test before the change. However, after the change to the base class, the sub-class fails its test. Because of this behavior, the base class is considered fragile because even a small change to it may have drastic effects for any sub-class which depends on it. The code in the sub-class is untouched, but is broken by the external change in the base class.

Note that despite its name, the problem really has to do with the implementation of the sub-class, which assumes intimate knowledge of how the base class works internally, and the language, which allows methods called by the base class to be overridden by sub-classes. In the latter case, sometimes this is intended, such as when the method is a virtual method, but this may not always be controllable by language features. If not, the base class may be unintentionally calling methods in the sub-class.

Several types of the fragile base class problem have been identified:


 * accidentally captured methods
 * unjustified assumptions in revision class
 * unanticipated mutual recursion
 * negation of inheritor specializations
 * direct access to the base class state

(Some of these may refer to the same type.)

Symptoms
Here is an oft-used example of the fragile bass class problem:

The following is wikicode, a former proposed standard pseudocode. (kinda... not quite yet)

Base class A { private int sum tally_one(n) { sum = sum + n } tally_many(list) { for each x in list { self.tally_one(x) } } }

Sub-class B of A { private int count tally_one(n) { count = count + 1 super.tally_one(n) } }

The idea of class A is that the variable  keeps a running sum of a set of integers. A single integer can be tallied to the running sum by calling. Many integers can be added at once by calling, and the class handles this internally by calling the   method for each integer in the list.

Sub-class B extends the functionality of A by keeping track of how many integers have been tallied, say, to be able to compute an average. Note that only  has been overridden, and   inherits directly from class A.  The class depends on   in class A to call the overridden   in class B to maintain the counter. As written, the class works correctly.

Now say that class A is redefined as follows:

Base class A { private int sum tally_one(n) { sum = sum + n } tally_many(list) { for each x in list { sum = sum + x } } }

The difference is that  has been redefined to add the integers directly to   instead of calling. Note that class A works exactly the same way before and after the change. However, consider class B: if  is called, the counter is incremented correctly, but if   is called with more than one argument in the list, the counter is incremented only once rather than by the number of arguments. Class B has become broken by the change to class A.

The fragile base class problem is language- and implementation-independent and the problem is related to, but different from, the fragile binary interface problem, which is a syntactic aspect of the problem and a technical issue. [2]

Solutions
The problem is lessened by enforcing single inheritance (as this reduces the complexity of the inheritance tree), and by the use of interfaces instead of base classes with virtual methods, as interfaces themselves do not contain code, only a guarantee that each method signature the interface declares will be supported by every object that implements the interface. However, the problem is a subject of continuing research.