Thursday, April 10, 2008

Dream Programming Language: Optional Interface Methods

Yet again, I find myself disliking abstract classes. I was creating a subclass of Java's OutputStream called PathalogicallyBufferedOutputStream (for testing purposes). I wanted to implement flush, which Eclipse nicely autocompleted to look like this:
public void flush() throws IOException {
// TODO Auto-generated method stub
That gave me enough pause to wonder... do I actually need to call the super method. It seems that I have 2 choices:
  1. Check the documentation
  2. Read the source code
Fortunately, Eclipse makes it easy to browse the JDK source code. It only took 2 seconds to verify that the base implementation, in fact, does nothing. Without Eclipse, I probably would have ignored it.

The no-op method stub is in the base class so that consumers of any OutputStream can indicate when the bytes that they have written so far form a semantically meaningful chunk. Somebody might be waiting for some data; this allows you to get it to her. The problem that I have as a deriver of OutputStream is that, without source code or good documentation, I have no idea whether I should or should not call the base method. This is not a problem with JDK-provided classes, but it could be a real bear with a third party library.

Some people might claim that you should "always call the base method". If course, that raises the question of at what point one should call the base method. Should you call it before or after your code? Perhaps you call it in the middle. I prefer to assume that I never have to call the base method, because I shouldn't be deriving from concrete classes, and I like to assume that method that I am overriding is simply a stub that I am free to customize.

If I were designing a language, I would want some notion of "optional interface methods." I want methods that I can declare on an interface (or perhaps an abstract base class) which implicitly have a no-op implementation. If I choose to implement one in a subclass or interface implementor (because I want to be notified when something happens), I would get the benefit of code completion. The caller is not burdened with the need to check to see if I've implemented the method, and the implementor is not burdened with the uncertainty of whether or not to call the base method.

1 comment:

Marisa said...

Thanks for writing this.