ClarityOfAccessModifiers
From APIDesign
An important aspect of any API is its Clarity. As API is about communication between the API writer and API user, the Clarity here needs to be applied to the communication. If the communication is clear, if the intention of the API writer correctly re-emerges in API users' heads then the API is clear enough.
Easy, one might think. However expressing yourself clearly in some language requires deep understanding of meaning of its words, sentences and other language constructs. This is true for English as well as Java. For example guess what the following API can be useful for:
Code from Arithmetica.java:
See the whole file.public class Arithmetica { public int sumTwo(int one, int second) { return one + second; } public int sumAll(int... numbers) { if (numbers.length == 0) { return 0; } int sum = numbers[0]; for (int i = 1; i < numbers.length; i++) { sum = sumTwo(sum, numbers[i]); } return sum; } public int sumRange(int from, int to) { int len = to - from; if (len < 0) { len = -len; from = to; } int[] array = new int[len + 1]; for (int i = 0; i <= len; i++) { array[i] = from + i; } return sumAll(array); } }
Is this class useful only for summing up two numbers, few numbers and a range? Not at all! With a little bit of invention one can sufficiently use it to compute factorial:
Code from Factorial.java:
See the whole file.public final class Factorial extends Arithmetica { public static int factorial(int n) { return new Factorial().sumRange(1, n); } @Override public int sumTwo(int one, int second) { return one * second; } }
At first this might look as perfect example of object oriented reuse, however if you are a maintainer of such API and you want to provide new enhanced version, this can easily lead to BackwardCompatibility nightmare (as described in AlternativeBehaviours).
Contents |
Fuzzy Access Modifiers
What is the cause of the problem? The problem is that in the world of API design access modifiers have different meaning than one could originally thought. Why is that? Because the public, protected, package private and private modifiers were originally approached from point of security. When I own something I can lock it, I can label it as confidential and show only to some friends or I can share only with my children. This sounds logical and from the point of security it even may be. Yet in combination with abstract and final (or virtual in other languages than Java) this can cause a complete nightmare when used cluelessly during API design.
Clarity is important. The easiest way to hurt clarity is to give one thing multiple meanings. Nobody can then know if someone's understanding of the thing is correct, full and the same as understanding of somebody else. In a fuzzy environment like this the author and user of an API cannot reliably communicate and understand each others intentions.
Meanings of public
Obviously the primary meaning is to allow anyone to call public method. However there is secondary, yet quite important additional interpretation: one can also re-implement the method in a subclass.
How dangerous this double meaning can be has been demonstrated in the Arithmetica example. What troubles such missing clarity can result in has been described in AlternativeBehaviours page. However better than knowing how to cure the problem, is to avoid it: eliminate public (without any additional modifier) methods from your API!
Meanings of protected
What a user of an API is supposed to think when there is a protected method? Is it something that shall be called or something that shall be overriden and implemented?
It can be both. Again, this can be seen as example of power of object oriented languages, but I can guarantee that users of your API will find such missing clarity confusing. What is this method good for? Am I supposed to use it to communicate with the super class or will super class call it when it finds the need to call it?
Nobody can easily tell the meaning of protected method in an API class. It is too fuzzy and in the name of Clarity it deserves to be avoided.
Meanings of public abstract
Methods marked as public abstract enforce every subclass to provide their implementation. There is no escape from this and as such this is the primary meaning of this pair of modifiers. Yet, the method is also public and as such it can be called by any user of the API. As such there is a second meaning of the method and needless to say that the clarity suffers.
Although not as bad as public, still there shall be no place for double meaning public abstract methods in an API, especially on objects that that every user of the API can get a reference to.
Single Meaning Access Modifiers
On the opposite side of fuzzy are the sets of modifiers that carry just a single meaning. These are the modifiers that good Java API should use the most. These guarantee that the vision of the API designer will be properly understand by the API user. Why? Because of the modifiers' clarity. Because there is only one way they can be useful in an API, it is clear that who ever finds at least one reason to use them, will find the right one.
Meaning of public final
Everyone who has a reference to an object with public final method can call it. That is the only meaning such method has. There is no other operation one could do with it. No subclassing, no overriding. Nothing. Just one purpose: call me!
Meaning of protected final
Methods marked with protected final combination cannot be overridden in subclasses. They can be only called. Because of being protected and not public they are targeted just for limited set of API users - only subclasses can call them.
This can be useful when one provides support classes (like AbstractList, etc.) which does a bunch of basic functionality. Subclasses then only slightly extend or tune what is premade. Then subclasses can initiate a change in the base superclass by calling protected final methods.
Again the message associated with these modifiers is clear and is just a single one: My children, call me!
Meaning of protected abstract
Abstract methods need to be implemented and that is also the primary meaning of protected abstract methods. Moreover, being protected they clearly indicate to all API users that external (not subclasses) API users just do not need to care. This pair of modifiers shouts to all subclasses: Implement me!
Eliminating Fuzzy Modifiers
Clarity of any API is important and with respect to modifiers this means that the more you eliminate the fuzzy ones (e.g. public, protected and public abstract), the more clear message users of your API will get without reading the documentation, API source code or studying existing examples.
Luckily it is not hard to stick just with single meaning modifiers. There even is an easy algorithm for converting fuzzy ones into methods with only public final, protected abstract and protected final modifiers.
In the name of clarity eliminate the fuzzy modifiers as much as possible.
Another Paradox of OO Languages
Interesting observation, when looking at fuzzy and single meaning' modifiers is that all the right ones are in fact composed of two words. While the wrong ones are often the single word ones. It should be the opposite way! The preferred ones shall be easier to use and shorter to type. The wrong ones, shall be longer, if they have to exist at all.
It seems that Java and many other object oriented languages were not designed to make life of API designers easy. Hopefully some future language will overcome this flaw and instead of practising Copy Based Design and instead of repeating this limitation of Java, the language comes up with new and more suitable modifiers. Why not have:
- callable to identify methods that every one can call but nobody can override
- slot to declare a not yet implemented method that has to (or may be) provided by subclass
- callback a method that subclasses can use to talk to super class
How long do API designers need to wait for such language? Or does some already exists? Anyone knows?
Discuss at LtU or here: <comments/>