Mike said:
Set implies those two, of course, and the fact that Subset implements Set is
part of its interface. The fact that I'm implementing Subset by subclassing
AbstractSet is an implementation detail.
This leads to an interesting question. Given that implementation details
should be hidden, perhaps the whole notion of inheritance and
subclassing needs an overhaul?
Basically, the fact that a class extends another class would become
"protected". It would no longer be legal for client code to do this:
A foo = new B();
A.someMethod();
given
public class A {
public void someMethod() { ... }
}
public class B extends A { ... }
If client code needed to polymorphically call someMethod you'd have to have
public interface A {
public void someMethod();
}
public abstract class AbstractA {
public void someMethod() { ... }
}
public class B extends AbstractA ...
A foo = new B();
A.someMethod(); // Legal again
Of course, the docs for B would note "implements A" rather than "extends
AbstractA". In fact, it would just note what's currently in "all
implemented interfaces". Unless you generated docs for "protected"
stuff, in which case its extending AbstractA would be noted. Actually,
I'd further suggest generating separate docs for the public interface of
a class and the protected one, with the former linking to the latter
where it exists, the latter not existing for final classes, and the
latter being focused on extenders and the former on users. So there'd be
say three new javadoc tags, @users, @implementers and @implementation;
the first would begin and the second would end the user-oriented
information, the latter also starting the implementer-oriented
information; the third would give implementation notes with a nice
IMPLEMENTATION NOTES: heading and be illegal on interfaces and their
members. The public interface doc for a class or interface would give
the public members and user-oriented information, while the protected
interface doc would give the public and protected members and
implementer-oriented information. Both would give the implementation
notes and the stuff prior to @user. Example:
/**
* This is the class summary and some info of interest to users and
* extenders.
* @users
* More information, geared towards users
* @implementers
* More information, geared towards extenders
*/
public class B extends AbstractA {
/**
* This is the method summary and some info of interest to
* users and extenders.
* @users
* Watch for the IOExceptions and possibly-null return value!
* @implementers
* If you override this, remember to fuzzle the foobar for
* the benefit of pre-version-2.0 clients, and to check baz
* for being out of range or null and throw an exception early.
* We don't want null being stored in the table and an exception
* only thrown when it's pulled back out; eager throwing ensures
* the stack trace points closer to the real error.
* @implementation
* Uses O(n log n) quicksort for performance
* @param baz whatever
* @return a Foo or null
* @throws IOException if something goes wrong
* @throws IllegalArgumentException if baz is out of range
* @throws NullPointerException if baz is null
*/
public Foo someMethod (Bar baz) throws IOException { ... }
/**
* Blah blah.
* @users
* Blah blah.
* // @implementers illegal here; final method!
*/
public final void someMethod ();
}
Output docs would look like
public class B implements A
This is the class summary and some info of interest to users and extenders.
More information, geared towards users.
<link to extender docs>
Method summary ...
public Foo someMethod (Bar baz) throws IOException
This is the method summary and some info of interest to users and extenders.
Watch for the IOExceptions and possibly-null return value!
IMPLEMENTATION NOTE:
Uses O(n log n) quicksort for performance
Parameters:
baz -- whatever
Returns: a Foo or null
Throws:
IOException if something goes wrong
IllegalArgumentException if baz is out of range
NullPointerException if baz is null
public void someMethod ()
Blah blah.
Blah blah.
Extender docs:
public class B extends AbstractA
This is the class summary and some info of interest to users and extenders.
More information, geared towards extenders.
public Foo someMethod (Bar baz) throws IOException
This is the method summary and some info of interest to users and extenders.
If you override this, remember to fuzzle the foobar for the benefit of
pre-version-2.0 clients, and to check baz for being out of range or null
and throw an exception early. We don't want null being stored in the
table and an exception only thrown when it's pulled back out; eager
throwing ensures the stack trace points closer to the real error.
IMPLEMENTATION NOTE:
Uses O(n log n) quicksort for performance
Parameters:
baz -- whatever
Returns: a Foo or null
Throws:
IOException if something goes wrong
IllegalArgumentException if baz is out of range
NullPointerException if baz is null
public final void someMethod ()
Blah blah.
Blah blah.
Note that the "final" on someMethod only appears in the extender doc for
the class B.
Actually there is one situation where it's sometimes desirable to have
an abstract class but no interface -- to force all implementations to
conform in some way, for instance by having a bunch of final public
methods and some protected non-final methods that some of the public
ones call. To support this I'd suggest allowing
public class X
public class Y extends X implements X
which shows as "implements X" on the user-docs, "extends X implements X"
on the extender docs, and makes the public interface of X part of that
of Y without exposing to users that X actually has some skeleton
implementation or using an XInterface that someone might implement
without extending X.
Note that the docs' "methods inherited from superclass" section would go
away in the user-oriented docs for a class, just showing all the public
methods of the class on an equal footing (even for the "Y extends X
implements X" case for methods of X not overridden by Y), but would show
them the traditional way in the extender docs and highlight the
finalness and protected/publicness of methods there.
The above would be better OO, I think, hiding more implementation
details from users and separating docs-for-clients and
docs-for-extenders. (Docs-just-for-maintenance-programmers being normal,
non-Javadoc comments in the source code.) The encapsulation is improved
and so is the documentation. Too bad it can't happen as Sun can't break
all that legacy code. But Sun could do the next best thing, by doing the
suggested javadoc changes and allowing "protected extends AbstractA". In
other words, the above but with "extends X implements X" -> "extends X"
and "extends X // but doesn't implement X" -> "protected extends X".
That won't break legacy code and overloads "protected" rather than
adding a new keyword.
(Another suggestion: allow declarations like
private Object obj !null;
public void foo (String str !null, int quuxCount) {...}
This overloads the existing keyword null and operator token ! and the
meaning is fairly clear: NPE should be thrown on attempting to assign a
null to the references, including via calls like foo(null, 3). It looks
fairly self-explanatory and saves programmers having to write explicit
tests for null when storing a value for use only later or else face NPEs
that don't point to where the problem happened.)