PROPOSAL: Improved Support for Optional Object Behaviors at Runtime
Neal Gafter
neal at gafter.com
Thu Mar 26 13:15:06 PDT 2009
This can be done today by creating a new interface that you implement
if you have any extensions...
interface Extension {
<T> T getExtension(Class<T> c);
}
and a utility class to get the extension...
T t = Extensions.getExtension(o, T.class);
if (t != null) {
... use t ...
}
This is not much boilerplate in the clients compared to your proposal,
and it is not a breaking change because it requires no change to
Object. If this pattern becomes wildly popular, one might recommend a
change in Object. As far as I know it isn't yet popular.
By the way, your implementation of getExtension will cause a
ClassCastException in clients that don't implement the type passed in
(i.e. your catch clause will never be executed). It also attempts to
use exceptions for normal control-flow, which would slow things down
due to stack traces being captured by the VM. A better implementation
would be
public <T> T getExtension(Class<T> c)
{
return c.isInstance(this) ? c.cast(this) : null;
}
If performance is a concern, this can be made about twice as fast (at
the expense of a generics warning) by replacing c.cast(this) by
(T)this.
Regards,
Neal
On Thu, Mar 26, 2009 at 12:08 PM, Alan Snyder <javalists at cbfiddle.com> wrote:
> Improved Support for Optional Object Behaviors at Runtime
>
>
> AUTHOR: Alan Snyder
>
> OVERVIEW
>
> FEATURE SUMMARY:
>
> This proposal would add a method to class Object to allow runtime access
> to optional object behaviors.
>
> MAJOR ADVANTAGE:
>
> As designs evolve and become more complex, it is useful to split out
> separable chunks of behavior whose support by an object might be optional.
> In current Java, the universally applicable technique for testing for and
> making use of optional behavior is the type cast. The type cast is limited
> by its tight coupling with the type hierarchy; as a result, because Java
> has single class inheritance, a class can not support an optional behavior
> defined by another class that is not already in its class hierarchy. In
> addition, because type casts cannot be simulated by an object, it is not
> compatible with delegation. For an object implemented by delegation to
> support optional behaviors using type casts, there would need to be one
> delegating class for each possible combination of optional behaviors.
>
> This proposal defines a method on class Object that can be used in place
> of type casts to test for and access optional behaviors. This proposal is
> not constrained by the type hierarchy of the target object, because it
> permits the optional behavior to be implemented using a different (but
> related) object. In addition, the determination of the available behaviors
> can be made dynamically. Specifically, this proposal allows a class
> implemented using delegation to mimic the set of optional behaviors
> supported by its delegate, even if the delegate is replaceable.
>
> MAJOR BENEFIT:
>
> By adding a method to class Object, this feature can be supported by any
> class, even existing Java platform classes, with no additional changes to
> their class hierarchies. Because the feature is universally available, the
> use of type casts for this purpose can be deprecated.
>
> This technique can be used to simply interfaces, or avoid making them more
> complex.
>
> MAJOR DISADVANTAGE:
>
> Any change to class Object freaks people out. This is the only change I
> can think of that is so obviously universal that it deserves to be in
> class Object.
>
> ALTERNATIVES:
>
> One alternative is to define this method in a new interface. This
> disadvantage of defining a new interface is that existing classes and
> interfaces would not support the method without themselves being changed.
> The other alternative is to add this method to classes and interfaces on
> an as needed basis. Either alternative forces programmers to use type
> casts in those cases where this method was not available. Also, new
> implementations of unchanged classes and interfaces would not be able to
> support this feature for existing clients of those classes and interfaces.
>
> EXAMPLE:
>
> Suppose a program wants to test an object "o" at runtime for an optional
> behavior defined by a class or interface "T". In current Java, the program
> could write:
>
> try {
> T t = (T) o;
> ... use t ...
> } catch (ClassCastException ex) {
> }
>
> Using the proposed feature, the program would write:
>
> T t = o.getExtension(T.class);
> if (t != null) {
> ... use t ...
> }
>
> The following examples are all hypothetical, but plausible to varying
> degrees. Note that many of them use instances of existing platform
> classes.
>
> // Test a list to see if it is observable, and get access
> // to the observable methods.
>
> Observable o = list.getExtension(Observable.class);
>
> // Test a file to see if supports metadata, and get access
> // to the metadata methods.
>
> FileMetadata fm = file.getExtension(FileMetadata.class);
>
> // Test file metadata to see if Mac OS file metadata is
> // supported. Note that the file might be on another
> // machine, so this call might succeed even on a non-Mac system.
>
> MacOSFileMetadata mfm = fm.getExtension(MacOSFileMetadata.class);
>
> // Test a file to see if it supports the new File API.
> // Note that using this approach the new File API does
> // not have to be an extension of the old API.
>
> java.nio.File nf = file.getExtension(java.nio.File.class);
>
> // Test a file to see if it is a directory, and get access to
> // the directory methods.
>
> Directory dir = file.getExtension(Directory.class);
>
> // Test a file to see if it is a symlink, and get access to
> // the symlink methods.
>
> Symlink s = file.getExtension(Symlink.class);
>
> // Test a file to see if it a directory and whether it provides
> // read and update access to the directory contents using the
> // List API (!).
>
> List<File> fs = (List<File>) file.getExtension(List.class);
>
> DETAILS
>
> The default definition in class Object would be:
>
> public <T> T getExtension(Class<T> c)
> {
> try {
> return (T) this;
> } catch (ClassCastException ex) {
> return null;
> }
> }
>
> Thus, if not overridden, the method has the same effect as the type cast.
> Thus it can be used in place of type casts even on instances of existing
> classes.
>
> Once this method is in place, programmers should be discouraged from using
> type casts for the purpose of testing for optional behavior.
>
> SPECIFICATION:
>
> JLS 4.3.2 would be changed to define this method.
>
> I'm not aware of other changes.
>
> MIGRATION:
>
> It would be advisable to convert appropriate type casts to invocations of
> this method in existing code.
>
> Once this method is available in class Object, other Java platform classes
> and APIs can be changed to take advantage of it.
>
> COMPATIBILITY
>
> BREAKING CHANGES:
>
> No matter what name is chosen for this method, some existing program could
> fail to compile if it defines a method with the same name and signature
> but (say) a different return type. Methods with class parameters are
> presumably uncommon.
>
> According to JLS 13.4.12, binary compatibility should not be broken
> because the method is public.
>
> EXISTING PROGRAMS:
>
> Existing classes automatically support this method to the same extent that
> they current support type casts for accessing optional behavior.
>
>
>
>
More information about the coin-dev
mailing list