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