Working a bit with Objective-C recently in my spare time, I’ve noticed they introduced something to the Objective-C Protocol declaration, which is the ability to specify that certain methods in a protocol1 are optional for implementation. I could think of more than one occasion where I could have used it, and even on JDK interfaces that could have used it too.
Case 1: Adapters and the empty implementation
Think of a case where you’d like to have a class to receive a list of interface implementations that performs an operation. Let’s call that method Performer.perform(Context context). The context is an object that could be used to transfer information to the performers. However, you might want your class to support a pre-performing operation called on all performers before they start, and a post-performing operation called on all performers after they finish. Our Performer interface should look like:
interface Performer { void perform(Context context); void prePerform(Context context); void postPerform(Context context); }
The problem is, that most performers would probably not like to implement the prePerform and postPerform methods; in fact, it’ll just be a hassle for them. So, what is usually done is create an abstract class called Adapter, right?
abstract class PerformerAdapter implements Performer { void prePerform(Context context) { } void postPerform(Context context) { } }
There. Now all our classes can extend PerformerAdapter, and be happy for not having to implement those pesky methods. This technique is widely accepted: we see it in the JDK and we see it in other respectable libraries. Probably means it’s good, right? Perhaps. Except it blocks them from extending some other class, so if that is required they’ll have to rewrite these empty methods themselves, and in any case it created some unnecessary class for our convenience, a class that I claim can be automatically generated. But let’s see another case first.
Case 2: preventing unimplemented calls from being made and the UOE
Imagine a different case. You have an interface, where some methods are just more important than others. You want to make sure the implementors of your API understand that they can provide more value to their implementations if they just implemented something a bit more; that way, you can write libraries that use this extra-API and those could be used only on supporting interfaces. For example, you want an interface that would load data from an arbitrary location, and return a Map of key-value string pairs. Your interface would probably have Loader.getData(). But suppose you also wanted to provide a way for that loader to reload periodically. But we’re in the 21st century! We have things like the concurrent library now and more specifically we can just return a Callable to be used with a ScheduledExecutorService, so that we won’t create our own threads for it. So, we’ll add a method called Loader.getPeriodicChecker(), which can be used to retrieve that Callable and add it to our users’ own executor – that way he can have the data reloaded at his preferred rate. So now our interface is complete:
interface Loader { Map<String , String> getData(); Callable<Void> getPeriodicChecker(); }
We’re back facing the same problem as before: most implementations might not bother with the checker. It might be difficult, impossible, or just not necessary. So again we’re writing an Adapter, only here we prefix it with Abstract, so it’s AbstractLoader:
abstract class AbstractLoader implements Loader { Callable<Void> getPeriodicChecker() { throw new UnsupportedOperationException("Reloading is not implemented for this Loader"); } }
Now our classes could extend AbstractLoader and not worry about it at all! Again, we see this in a day-to-day interface in the JDK, and it’s a common practice. As this is truly ugly, some would remove the getPeriodicChecker from the original Loader interface and create an additional interface, called PredicallyCheckedLoader:
interface Loader { Map<String , String> getData(); } interface PeriodicallyCheckedLoader extends Loader { Callable<Void> getPeriodicChecker(); }
Can’t say it’s a bad solution. It just overcomplicates things a bit – now if I wanted to call that method I need to downcast, but on the other hand I am safe from runtime exceptions.
A possible solution – The @Optional annotation
First, let me say that while thinking about this post I have found a thread discussing a similar idea of an @Optional annotation already; this discussion was very short and died down prematurely I believe. Consider the previous cases with this annotation:
interface Performer { void perform(Context context); @Optional void prePerform(Context context); @Optional void postPerform(Context context); } interface Loader { Map<String , String> getData(); @Optional(exception=true, message="Reloading is not implemented for this Loader") Callable<Void> getPeriodicChecker(); }
Note that the exception default value is false, so it defaults to doing nothing. Together with modern processing or good old AspectJ, this could be used to generate code that implements these methods automatically for implementing classes, in case they haven’t been implemented. Additionally, I can imagine a utility class could be used to check whether an optional method has been implemented or was it just auto-completed by the code generator.
FileLoader loader = new FileLoader("myfile.csv"); if (Optionals.isImplemented(loader, "getPeriodicChecker")) { myExecutor.schedule(loader.getPeriodicChecker(), 1, TimeUnit.HOUR); }
As of now, I can’t think of another way other than reflection to do this, so there’s a bit of ugliness here; however, consider that this code is always safe, even if the method changed it’s name without updating the string referring to it. I can think of a different type of utility that would just try to call the method and perform an operation on success, though:
Optionals.tryOptional(loader.getPeriodicChecker(), new ResultListener() { void onSuccess(Callable<Void> result) { myExecutor.schedule(result, 1, TimeUnit.HOUR); } void onFailure(Exception e) { logger.log(e); } }
Conclusions
Annotations and compile-time code generation allow us to make our lives as developers much easier than they are right now. I think the ability to specify interface methods as optional allows for more flexibility, and is not an “aberration”, as someone in that forum post wrote. It could allow us to do what we sometimes do anyway, without all the hoops and loops we have to go through in the name of “good design”. After all, this is just boilerplate code; the “good design” of adapter and abstract classes is there to allow us to minimize the boilerplate code damage, not because it’s “an OOP thing”. These are my thoughts – I’d love to hear your ideas on the subject though!
Protocols are the Objective-C equivalent of a Java interface; this is confusing at first, because in Obj-C there is something called an “interface” and has no real equivalent in Java. The Obj-C interface is more like the structure definition of a concrete class, like a header file in C++. (back)
Liked Chaotic Java? It's free! But I also make some other things that aren't, which you might like. Like Firewall, a rule changing, turn based strategy game for iOS.
July 24th, 2010 at 11:16 am
[...] This post was mentioned on Twitter by waman 10da, Aviad Ben Dov. Aviad Ben Dov said: ChaoticJava: The @Optional interface method http://goo.gl/fb/XtTD0 [...]
July 27th, 2010 at 11:12 am
Maybe it is already here, in the form of trait in Scala
http://www.scala-lang.org/node/126
Ido.
July 27th, 2010 at 11:23 am
Perhaps. I’m not really familiar with traits, but it seems to do the trick and even more, such as default implementations based on other implementations or even interface methods. The question was not whether it exists in other languages, as it does; as I mentioned above, Objective-C has it. The question was whether it exists for Java specifically.
By the way, I wonder if with the introduction of Clojures / Lambdas in Java, the level of flexibility for default implementations could be achieved for the @Optional annotation as well…
August 26th, 2010 at 9:23 pm
You might be interested to read about “defender methods”, scheduled for Java 7.
September 2nd, 2010 at 9:53 am
@Daniel: I have actually! I read about it a little while *after* writing this post, unfortunately, but I don’t know if I’d change the post other than mentioning that feature in Java 7. My plan is to write a shorter post about defenders soon. Stay tuned!