User:Yuqiufeng/sandbox

From Wikipedia, the free encyclopedia

Problem Definition[edit]

Fragile base class is an architectural problem which sometime occurs in object-oriented programming taking code inheritance as an implementation of code reuse mechanism. We often refer to a fragile base class when some base class seems to be safe to modify, but causes the subclass to malfunction(in terms of Exception/ Errors) in return. And the malfunction cannot be detected only by rechecking an isolated class here(base or subclasses) because they are highly coupled.

One solution can be using Abstract classes/Interface rather than inheritance, which means we do not implement anything in the base class; instead we only declare methods in base classes.

Another possible solution is to make the member variables private in the class where it was declared and only allow access from subclasses through getters and setters. Many languages could achieve that so that subclasses can control which inherited methods are exposed publicly.

These changes may prevent subclass malfunction by making changes to base class since we are moving the implementation details into subclasses and have put restrictions on the methods and variables exposed to subclass.

Java example[edit]

The following Java example is written in the Java programming language from Goodbye Object Oriented Programming and shows how a seemingly safe modification of a base class can cause an inheriting subclass to malfunction[1].

import java.util.*;

public class Array {
	private ArrayList<Object> a = new ArrayList<Object>();

	public void add(Object element) {
		a.add(element);
	}

	public void addAll(Object elements[]) {
		for (int i = 0; i < elements.length; ++i)
			a.add(elements[i]);
	}
}

We have a base class called Array, in this class, two methods have been implemented, add and addAll.

public class ArrayCount extends Array {
	private int count = 0;

	@override
	public void add(Object element) {
		super.add(element);
		++count;
	}

	@override
	public void addAll(Object elements[]) {
		super.addAll(elements);
		count += elements.length;
	}

}

Now we have a subclass called ArrayCount which extends Array. In this class. the methods add() and addAll( ) are overridden by the subclass. The add( ) method will add one element to the array, and the addAll method will call add( ) in order to add multiple elements to the array. The ArrayCount class is the concrete implementation of Array class. The only difference between ArrayCount and Array is that, ArrayCount will count the number of elements after adding an element.

public void addAll(Object elements[]){
    for ( int i = 0; i < elements.length; ++i){
        add(elements[i]);
    }
}

When using the above code to replace the addAll( ) method in the base class, addAll( ) method in ArrayCount calls the addAll( ) method in its parent class. The parent class addAll( ) method gets executed, but instead, it calls the method add( ) in the subclass since there is an overridden add( ) method in the subclass. The count variable gets updated when every object is being added but after the super.addAll(elements), the count is added with the elements.length for another time. Therefore, it causes the subclass to increment two times, which was not expected by the programmer.

Theoretical Solutions[edit]

Theoretically, there are three different categories to prevent fragile base class problem[2]:

Documentation[edit]

One way to prevent fragile base class problem is through the usage of documentation. By well documenting each class features, developers can obtain much more comprehensive information on methods and their functionality, so that it would be easier for the developers to decide whether overriding a subclass will lead to a potential side effect.

Languages such as Ruby uses formal specification to make sure the safety of method calling and overriding in the base-class by the methods of its subclasses. Some of the formal specifications, including the precoditions and postconditions and invariants are automatically generated by the Java modeling Language (JML).

Restriction[edit]

One of the most likely situations which can lead to a potential fragile base class problem is the usage of inheritance and self-recursion in the object-orientated languages. In order to prevent that, there are four restrictions developers might want to take into consideration.

  1. There should not be any cycles between a base class and its subclasses.
  2. Methods of a base class should not make any additional assumption regarding other methods.
  3. All subclasses should consider only the behavior of the methods defined in the base class.
  4. All subclasses should not access the state of a base class directly.

New Mechanisms[edit]

Method inheritance provides a powerful mechanism for the programmers to reuse the code, and therefore, improved the code efficiency. However, there exist some new mechanisms which also improve the code efficiency and prevent the fragile base class problem as the same time. Instead of overriding a particular method from the base class, Ozaki H, Gondow K, and Katayama T (2003)[3] suggested that programmers should decompose inheritance into class addition and class refinement.

Different Language Solutions[4][edit]

  • Objective-C has categories as well as non-fragile instance variables.
  • Component Pascal deprecates superclass calls.
  • Java, C++ and D allow inheritance or overriding a class method to be prohibited by labeling a declaration of a class or method, respectively, with the keyword " final". In the book Effective Java, author Joshua Bloch writes (in item 17) that programmers should "Design and document for inheritance or else prohibit it".
  • C# and VB.NET like Java have "sealed[5]" and "Not Inheritable[6]" class declaration keywords to prohibit inheritance, and require a subclass to use keyword " override" on overriding methods,[7] the same solution later adopted by Scala.
  • Scala require a subclass to use keyword " override" explicitly in order to override a parent class method. In the book "Programming in Scala, 2nd Edition", the author writes that (with modifications here) If there was no method f(), the client’s original implementation of method f() could not have had an override modifier. Once you add the f() method to the second version of your library class, a recompile of the client code would give an compile error instead of wrong behavior.
  • Julia allows only subtyping of abstract types and uses composition as an alternative to inheritance. It however has multiple dispatch.

See also[edit]

References[edit]

  1. ^ Scalfani, Charles. "Goodbye, Object Oriented Programming". Medium. Medium. Retrieved 13 February 2017.
  2. ^ Sabané, Aminata; Guéhéneuc, Yann-Gaël; Arnaoudova, Venera; Antoniol, Giuliano (2016). "Fragile base-class problem, problem?". Empirical Software Engineering: 1.
  3. ^ H, Ozaki; S, Ban; K, Gondow; T, Katayama (2003). "An environment for evolutionary prototyping Java programs based on abstract interpretation". Software Engineering Conference: 362-370.
  4. ^ "FRAGILE BASE CLASS". eBook Cloud Library. World Heritage Encyclopedia.
  5. ^ "Abstract and Sealed Classes and Class Members (C# Programming Guide)". msdn.microsoft.com.
  6. ^ "NotInheritable (Visual Basic)". msdn.microsoft.com.
  7. ^ https://msdn.microsoft.com/en-us/library/ebca9ah3.aspx

External links[edit]