This week's book giveaway is in the OO, Patterns, UML and Refactoring forum. We're giving away four copies of Refactoring for Software Design Smells: Managing Technical Debt and have Girish Suryanarayana, Ganesh Samarthyam & Tushar Sharma on-line! See this thread for details.
I was reading Dr. Dichotomy's (Eamonn McManus) Development Diary: Java API Design Guidelines. agreeing with all the major points until I came to Interfaces are overvalued: A type should only be an interface if you have a good reason for it to be [one]. He lists three common "good reasons":
Callbacks. He gives Runnable as an example.
Multiple Inheritance. He gives Integer having types Comparable and Number as an example.
Dynamic Proxies. You cannot construct a dynamic proxy for an abstract class.
So I thought -- if they're overvalued, to the devil with them! Would Java change much if it didn't have interfaces? To consider the previous points:
Callbacks. Isn't this more of a convenience than a necessity? If need be,
an inner object can extend a "callback" abstract class.
Multiple Inheritance. Is Comparable a compelling example? Once can get by with a Comparator.
Dynamic Proxies. In Java w/o interfaces, perhaps dynamic proxies could be reintroduced
for "pure" abstract classes. Looking a little harder at the second point, what about Serializable? Hmmm... Serialization is so central to the language perhaps Object should have a method isSerializable() with the default implementation returning false. (While I'm at it, I think I'll consign wait and notify methods only to class HoareMonitor, but I digress.)
As another example, consider the collection framework. RandomAccess could be redone as a method of List: isRandomAccess(), if it really is needed. Besides that, the only place where "multiple inheritance" raises its ugly heads is when LinkedList implements both List and Queue, but you could get around that by adding this method to LinkedList instead:
Queue asQueue() //or getQueueView()
The only loss of expressiveness that I see here is that you can't downcast this Queue back to a LinkedList, but perhaps that's a good thing.
Finally, considering Java's IO streams, the main use of multiple inheritance is when RandomAccessFile implements both DataInput and DataOutput (shades of C++'s diamond for iostream...). Again, we can fix that with views:
DataOutput asDataOutput() DataInput asDataInput()
So is this all a crazy minimalist's dream? Would Java break without interfaces? Or would it have been left out as too complicated if nested classes had gotten introduced first?
Without MI (and nothing to replace it), the software I write would become much less flexible (and/or more complex), so I'd vote against it.
The soul is dyed the color of its thoughts. Think only on those things that are in line with your principles and can bear the light of day. The content of your character is your choice. Day by day, what you do is who you become. Your integrity is your destiny - it is the light that guides your way. - Heraclitus
Joined: Sep 16, 2005
Thanks for the reference to the ISP article, but in the intial example, TimedDoor, there are two adapter pattern solutions (the object form and the class (MI) form: While the MI form is shorter, the object form makes the Timer an implementation detail, so it has less surface area. If client code creates a TimedDoor2 using new, it should be recompiled if the TimerClient interface changes, which seems to be what the author is trying to avoid.
Again, I like interfaces, so I put this forward as only a thought- experient: how much would Java or your coding style change if interfaces disappeared? I think I would have gone the object adapter route in this example, so I wouldn't miss "MI" here.
Originally posted by Jeff Albrechtsen: I was reading Dr. Dichotomy's (Eamonn McManus) Development Diary: Dynamic Proxies. In Java w/o interfaces, perhaps dynamic proxies could be reintroduced for "pure" abstract classes.
The language could have been so designed that the minute there is an abstract class with no method, multiple-inheritability and dynamic-proxifiability would automatically get enabled. But I am not sure this would be elegant, so a separate syntactic construct did make sense.