Improved Support for Optional Object Behaviors at Runtime
Derek Foster
vapor1 at teleport.com
Sat Mar 28 15:17:30 PDT 2009
First of all, I would like to say that I understand the problem you are trying to solve, and I like the general approach of your solution.
I have seen the same thing done less well in the Eclipse framework. where it is used all over the place. (Their solution doesn't use generics, and does use a custom interface). I have appended the definition of the relevant interface below, in case you are curious.
I like your approach of adding a method to Object. This lends itself to a wide variety of interesting uses even involving existing standard library classes. I have had a number of cases where I have had to "roll my own" interface of this sort where using a standardized one would have been better and more versatile.
I am less sure that I care for the practice of returning null rather than throwing a ClassCastException. It is very common for people to neglect to check for null, and for code to therefore suffer NullPointerExceptions at a much later point in the code when someone tries to use an interface that they had assumed would be present. This can be quite difficult to track down. A ClassCastException at the point of call localizes the problem very tightly, and makes debugging easier. Thus, I would rather see something like:
boolean hasExtension();
T getExtension(Class<T> extension) throws ClassCastException;
so that those who forget to ensure the existence of the extension they are trying to use will have their thread throwing ClassCastException and thus aborting future processing, rather than continuing on as if nothing had happened and eventually getting a NullPointerException when code later (possibly much later) tries to make a call thorugh the interface. Those who want to be sure exceptions won't get thrown can do something like:
if (obj.hasExtension(Foo.class)) {
Foo obj = obj.getExtension(Foo.class)); // Guaranteed not to throw ClassCastException now
}
Note that a hasExtension method can also be useful in other contexts:
void func(Thing obj) {
assert obj.hasExtension(Foo.class);
... do stuff ...
}
One significant concern: I am not sure that 'getExtension' is an uncommon enough name that it could be added to Object without blowing anybody's existing class library out of the water, although I appreciate that the method signature is unusual enough that this is not as likely as it could be. (There might be some unexpected overloading of it, however.) I would still prefer something much less common that is much less likely to be used already.
Derek
Here's the interface from Eclipse that I mentioned. A huge number of objects in the Eclipse framework and its plugins extend this, either directly or indirectly.
package org.eclipse.core.runtime;
/**
* An interface for an adaptable object.
* <p>
* Adaptable objects can be dynamically extended to provide different
* interfaces (or "adapters"). Adapters are created by adapter
* factories, which are in turn managed by type by adapter managers.
* </p>
* For example,
* <pre>
* IAdaptable a = [some adaptable];
* IFoo x = (IFoo)a.getAdapter(IFoo.class);
* if (x != null)
* [do IFoo things with x]
* </pre>
* <p>
* This interface can be used without OSGi running.
* </p><p>
* Clients may implement this interface, or obtain a default implementation
* of this interface by subclassing <code>PlatformObject</code>.
* </p>
* @see IAdapterFactory
* @see IAdapterManager
* @see PlatformObject
*/
public interface IAdaptable {
/**
* Returns an object which is an instance of the given class
* associated with this object. Returns <code>null</code> if
* no such object can be found.
*
* @param adapter the adapter class to look up
* @return a object castable to the given class,
* or <code>null</code> if this object does not
* have an adapter for the given class
*/
public Object getAdapter(Class adapter);
}
More information about the coin-dev
mailing list