InvisibleAbstractMethod

From APIDesign

(Difference between revisions)
Jump to: navigation, search
Line 29: Line 29:
<source lang="bash">
<source lang="bash">
-
Warning: public class api.AbstractClass can't be extended because contains the following member:
+
Warning: public class api.AbstractClass cannot be extended because contains the following member:
method abstract void api.AbstractClass.youWillNeverImplementMe()
method abstract void api.AbstractClass.youWillNeverImplementMe()
</source>
</source>

Revision as of 12:07, 20 March 2012

Having an abstract class with package private abstract method effectively prevents anyone using such API to subclass it. This can be considered as good API design pattern, especially if such pattern is used since initial version of the API.

However it can also turn into a huge anti-pattern. Adding first package private abstract method into an abstract class is in fact an incompatible change. If the class used to be subclassable before, this prevents the subclassing and as such classes that used to compile may compile no more.

If the original version of a class contains one abstract method:

package api;
/** version 1.0 */
public abstract class AbstractClass {
    public abstract void subclassMeAndImplementMe();
}

and later somebody adds a new implementation detail:

package api;
/** version 2.0 */
public abstract class AbstractClass {
    public abstract void subclassMeAndImplementMe();
    // hidden, not public new method
    abstract void youWillNeverImplementMe();
}

then we are facing an incompatible change. Inspite of not changing the visible methods of the class at all!

The hidden catch is that tools like Sigtest are unlikely to catch this situation, as they don't care about package private methods! Sigtest only emits a warning:

Warning: public class api.AbstractClass cannot be extended because contains the following member:
  method abstract void api.AbstractClass.youWillNeverImplementMe()

However warning is not enough, this is an incompatible change and it should be reported as such. The error should be same as in case somebody makes the youWillNeverImplementMe method public abstract. In such situation sigtest properly reports error:

Class api.AbstractClass:
  "E5.2 - Adding abstract methods" : method public abstract void api.AbstractClass.youWillNeverImplementMe()


Some people complained about unnecessary complexity of various OOP access modifiers - and they were likely right, but this case is worse (from the point of an API designer) - a change to an implementation detail may change the published APIs!

Personal tools
buy