PROPOSAL: Improved Support for Optional Object Behaviors at Runtime

Alan Snyder javalists at cbfiddle.com
Thu Mar 26 12:08:55 PDT 2009


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