User:Mordomo/FBC

From Wikipedia, the free encyclopedia

Fragile base class[edit]

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[edit]

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[edit]

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 sum keeps a running sum of a set of integers. A single integer can be tallied to the running sum by calling tally_one. Many integers can be added at once by calling tally_many, and the class handles this internally by calling the tally_one 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 tally_one has been overridden, and tally_many inherits directly from class A. The class depends on tally_many in class A to call the overridden tally_one 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 tally_many has been redefined to add the integers directly to sum instead of calling tally_one. Note that class A works exactly the same way before and after the change. However, consider class B: if tally_one is called, the counter is incremented correctly, but if tally_many 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[edit]

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.

External links[edit]

[1] Why Extends is Evil - An example in Java

[2] Leonid Mikhajlov and Emil Sekerinski. A Study of the Fragile Base Class Problem, 1998.

[3] Mira Mezini, Jens U. Pipka, Thorsten Dittmar, and Wim Boot. Approaching the Fragile Base Class Problem by Binary Analysis, 1993.