User:Mordomo/FBC
From Wikipedia, the free encyclopedia
Contents |
[edit] 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.
[edit] 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.)
[edit] 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 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]
[edit] 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.
[edit] External links
[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.