Improved Support for Optional Object Behaviors at Runtime (original) (raw)
Alan Snyder javalists at cbfiddle.com
Fri Mar 27 12:11:36 PDT 2009
- Previous message: PROPOSAL: 'forget' keyword (beta)
- Next message: PROPOSAL: Using Ordinary Syntax for Reflective Method Invocations
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Perhaps a few more words of explanation would help clarify the proposal. I will write them using a FAQ format.
- What is the problem being solved?
The goal of the proposal is to better support objects with optional behaviors, meaning that the client must perform some sort of test to see if the the optional behavior is defined and also somehow get access to the optional behavior using an appropriately typed variable (one whose type is the class or interface that specifies the optional behavior). Better means better than the current solution of using a type cast.
- The client code that you recommend (to access optional behavior in an object) doesn't look that different than what people would write today. What is the point? Are you saying that an if statement is better than an exception handler?
Actually, I do think an if statement is better than an exception handler in this case, but that is incidental. Changing the code that the client writes is necessary to access the new features of this proposal. Using the new style, the client invokes a method. Using the old style, the client uses a primitive operator (type cast). The advantage of invoking a method is that method invocation is extensible, whereas the behavior of the primitive operator is fixed (or limited) to what the Java Language Specification says. When I say that method invocation is extensible, I mean that the code that gets executed is defined by the developer of the class of the target object.
- The method definition that you proposed (for class Object) looks just like the old style code in the client. What is the point?
It is completely intentional that the code looks the same, because that is how backward compatibility is supported. What this means is that if a client program is changed to invoke the getExtension method instead of using a type cast, the program will behave exactly as it did before, when it is using old objects (that is, objects whose implementations have not been changed to take advantage of this proposal).
However, the proposed method definition is just a default method definition. A class can be written that overrides the getExtension method, and it can do things that a type cast cannot do.
- What can a custom implementation of the getExtension method do that a type cast cannot?
Good question. The main thing that a method can do that a type cast cannot is return a reference to a different object than the original target object. If you haven't thought about this sort of thing before, this idea might sound strange, but it is really not. The new object would almost certainly share data with the original object.
Here's an example from current Java: Any collection object can return an iterator that provides the elements of the collection one at a time, and may even allow elements to be removed from the collection. The iterator is a different object than the collection, but they share access to the same underlying data. Such sharing is not only more efficient than making a copy of the data for the iterator, it is essential to allow the iterator to remove elements from the collection.
Because the method can return a different object, it can support class parameters that are unrelated to the class of the target object. As a simple, perhaps fanciful example:
File f = ...;
List l = (List) f;
This cast will always fail, because File does not implement the List interface (and probably never will).
However, consider this call:
File f = ...;
List l = f.getExtension(List.class);
This call might succeed. It won't succeed on an ordinary File, but I could write a subclass of File for which it would return a List (say, of the files in a directory, if the File represented a directory).
- You say this proposal better supports delegation. What is delegation and why is it important?
If you have never encountered delegation before, you probably need to do some reading before you will fully appreciate it. In a nutshell, delegation is an alternative to subclassing as a way of customizing object behavior. You write a new object that supports the same methods as the old object, and implement the methods by forwarding them to the old object, but the new class may add new methods, or do other things in the old methods, or alter method parameters or results. This concept is also called wrapping. People who know a lot about delegation know that Java does not support delegation in its full glory, but even a limited form can be useful.
The problem with type cast is that it can be very hard to make a wrapper object that simulates the behavior of the original object when a client uses a type cast on the wrapper object. The reason it is hard is that no wrapper class code gets executed when the type cast is done. Instead, the wrapper class must be constructed to simulate the relevant aspects of the class hierarchy of the original object.
- OK, so the getExtension method is useful, but why not just define it in a new Interface instead of adding it to class Object?
This can certainly be done, and it has. I know of four public APIs that have included a method similar to getExtension in their interfaces, and there are probably many more. The unwrap method in java.sql.Wrapper has already been mentioned as one example.
However, defining getExtension in a new interface means that it can be used only on new APIs that contain this method or old APIs that have been modified to contain this method.
By adding this method to class Object, any class developer can now or in the future add optional behaviors to their class without changing the class hierarchy or the API.
This ability is available to Java platform class developers as well as to application class developers. I have not looked, but it would not surprise me that some JSR expert group is considering adding some new behavior to an existing Java platform class. If they used the getExtension method to provide access to that new behavior, then they would not have to make any change to the existing API, only to the documentation. Because the API is unchanged, any application created subclasses would continue to work and to compile. They would simply return null when asked for the new extension.
In effect, this one small API change now can remove the need to make many future API changes.
- Extra credit: If the basic problem is that type cast is not extensible, why not make it extensible?
Excellent question. Feel free to submit a proposal!
- Previous message: PROPOSAL: 'forget' keyword (beta)
- Next message: PROPOSAL: Using Ordinary Syntax for Reflective Method Invocations
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]