@OverrideShouldInvoke

Archie Cobbs archie.cobbs at gmail.com
Thu Feb 9 16:07:02 UTC 2023


Just throwing this out there - I'm curious whether this idea resonates with
anyone else... or alternately offends...

First, a big picture observation:

There is a lot of "activity" in Java centered around the
superclass-subclass relationship. For example, we have the protected
keyword. We have the final keyword. We have a bunch of rules around how
constructors are allowed (or not allowed) to invoke super(). We have
@Overrides. We have abstract methods that force behavior on subclasses.

Basically, all of this stuff amounts to a somewhat ad hoc "API" that a
superclass defines and a subclass uses (and in some cases, vice-versa).

But this "API" is not always clearly or fully defined. For example, bugs
caused by 'this' escapes result from what can be described as an ambiguity
in the "API" between superclass and subclass.

I guess I'm just saying that this "API" and how we define it (or fail to
define it) is an area of interest to me.

OK, back to earth...

Here's a proposal that addresses one more little bit of this "API". I'm on
the fence as to whether this would be worthwhile and am curious what others
think.

The problem is this: often a superclass method foo() implements some
important superclass functionality, but it is not final so that it can be
overridden. In these cases, the superclass often wants to be able to
specify "If you override this method, then you should also invoke
super.foo() at some point unless you really know what you're doing". An
example of such a method is Object.finalize().

There are arguments that such methods are bad style - instead, there should
be a separate empty method provided for subclasses to override. So this
idea would have to be weighed against that. But regardless, today there are
lots of examples of such methods out there already.

The rough proposal is:

   - Add a new annotation @OverrideShouldInvoke. If a method Sub.foo()
   overrides a superclass method Sup.foo() that has an @OverrideShouldInvoke
   annotation, and nowhere in Sub.foo() does it invoke Sup.foo() (via a
   super.foo() expression), then an error occurs.
   - Add a new property boolean withoutInvokingSuper default false to the
   @Overrides annotation that allows Sub.foo() to suppress this error if it
   "really knows what it's doing".

For simplicity, we'd only count invocations of the overridden method
exactly, not some overloaded variant. So for example if an override of
ArrayList.add(E) invoked super.add(int, E), that wouldn't count. Or, if you
wanted to get fancy, you could make this optional via something like
@OverrideShouldInvoke(allowOverloads = true).

Here's are some examples of where you might want to use this:

public class Object {

    @OverrideShouldInvoke
    protected native Object clone() throws CloneNotSupportedException;

    @OverrideShouldInvoke
    protected void finalize() throws Throwable {
        ...
    }
}

public class FileOutputStream extends OutputStream {

    @OverrideShouldInvoke
    public void close() throws IOException {
        ...
    }
}

public abstract class AbstractExecutorService implements ExecutorService {

    @OverrideShouldInvoke
    public Future<?> submit(Runnable task) {
        ...
    }
}

Thoughts?

-Archie

--
Archie L. Cobbs
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20230209/9148989e/attachment.htm>


More information about the amber-dev mailing list