PROPOSAL: Improved Support for Optional Object Behaviors at Runtime (original) (raw)

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 getExtension(Class 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 fs = (List) file.getExtension(List.class); DETAILS The default definition in class Object would be:  public T getExtension(Class 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