
![]() | |
![]() The JavaLanguage Team JavaSoft, Sun Microsystems, Inc. Introduction The newest version of the Microsoft Visual J++ developmentenvironment supports a language construct calleddelegates orbound method references. This construct, and the new keywords It is unlikely that the Java programming language will everinclude this construct. Sun already carefully consideredadopting it in 1996, to the extent of building and discarding workingprototypes. Our conclusion was that bound method references areunnecessary and detrimental to the language.This decision was made in consultation with Borland International,who had previous experience with bound method references in Delphi Object Pascal. We believe bound method references areunnecessary because anotherdesign alternative,inner classes, provides equal or superiorfunctionality. In particular, inner classes fullysupport the requirements of user-interface event handling, and havebeen used to implement a user-interface API at least as comprehensiveas the Windows Foundation Classes. We believe bound method references areharmful because they detractfrom the simplicity of the Java programming language and thepervasively object-oriented character of the APIs. Bound methodreferences also introduce irregularity into the language syntax andscoping rules. Finally, they dilute the investment in VM technologiesbecause VMs are required to handle additional and disparate types ofreferences and method linkage efficiently. It has been clear from the outset that the original language neededsome equivalent of method pointers in order to support delegation and"pluggable" APIs. James Gosling noted this in his keynote at thefirst JavaOne conference. The keydesign question at the time was whether we needed a specializedfunction pointer construct, or whether there was some new way to useclasses to meet the requirements. In the summer of 1996, Sun was designing the precursor towhat is now the event model of the AWT and the JavaBeans component architecture. Borland contributedgreatly to this process. We looked very carefully at Delphi ObjectPascal and built a working prototype of bound method references inorder to understand their interaction with the Java programminglanguage and its APIs. Working through the implementation of bound method referencesshowed us how foreign they are to a pure object-oriented model. Wediscovered the following limitations:
Although a native code compiler like Delphi Object Pascal canimplement bound method reference calls with a couple of instructions,there is no comparably efficient way to implement them on anunmodified Java VM. Our prototype therefore used compiler-generatedadapter classes. This solution was fast, but pointed to an evenbetter solution -- improving support for adapter objects of all kinds. With these results in hand, the designers of the Java programminglanguage decided to introduce inner classes. Inner classes,especially anonymous inner classes, make it possibleto create and use adapter objects as easily as bound method references,while retaining all of the benefits of a uniformly class-based solution. We have argued above that adapter objects, using inner classes, are abetter solution than bound method references. Let's now take a lookat adapter objects in action. We will examine two cases from the Javaplatform APIs, contrasting the solution we adopted with an alternativebased on method references. Programs that use delegation patterns are easily expressed with innerclasses. In the AWT event model, user-interface components send eventnotifications by invoking methods of one or more delegate objects thathave registered themselves with the component. A button is a verysimple GUI component that signals a single event when pressed. Hereis an example using the
When the user clicks on the button, it invokes the In a language that uses bound method references, the correspondingcode would be quite similar. Again, a button delegates a click to anaction method. In this case, the delegate is an enclosing object.Keeping the identifiers the same to make the remaining differencesstand out clearly:
The key conclusion is quite simple:Any use of a bound methodreference to a private method can be transformed, in a simple andpurely local way, into an equivalent program using a one-memberprivate class. Unlike the original, the transformed program willcompile under any JDK 1.1-compliant Java compiler. Method references require the programmer to flatten the code of theapplication into a single class and choose a new identifier for eachaction method, whereas the use of adapter objects requires theprogrammer to nest the action method in a subsidiary class and choosea new identifier for the class name. In terms of program complexity, thedifference is four extra tokens and some indentation for theadapter-object pattern -- a negligible difference. It is sometimes more convenient for the programmer to use ananonymous inner class. Anonymous classes make the code using anadapter object as short as the code using a method reference. Thoughit requires the same number of tokens as a method reference,an anonymous adapter object avoidsthe need for an extra identifier by nesting the action method directlywithin the expression that attaches it to the button:
Note that this style of event configuration puts the button event methodas close as possible to the initialization of the button. By contrast,when named classes or methods are used, the event method can end up faraway from the initialization, because it must be placed in the enclosingclass, and must be mixed with other event methods for the same panel. With either kind of delegate, whether an adapter object or a methodreference, the programmer is free to ignore the separate identity ofthe delegate object and regard it as an integral part of the panelclass, i.e., Adapter objects also find natural uses in non-GUI APIs. For example,the JDK 1.2 class libraries provide a routine for sorting an array of objects. Theroutine takes an argument that lets the programmer specify how tocompare the array elements. This argument, called acomparator,is an object with a method that is invoked by the sort routine to comparepairs of array elements. It is of the following type: public interface Comparator { public int compare(Object o1, Object o2);}As an interface,
Since we used an anonymous class, the comparison method is placed withinthe call to the sort routine, where it is used just once.If the delegate were created with a boundmethod reference, the sort routine would have to be given a unique nameand placed in the body of the enclosing class, possibly far fromits actual point of use:
Note also that the bound method reference in this case includes aspurious reference to the enclosing class, which is not actually usedby the algorithm. If the delegate outlives theenclosing object this feature can cause unexpected storage retention.More generally, it is poor program organization to place this methodin the enclosing class because it does not operate on the class. Allthese problems stem from the relative inflexibility of bound methodreferences as compared to inner classes. Storage retention is not a problem with the local adapter object.Since the object does not actually use all the values visible to it(like The Visual J++ delegate construct provides a convenient multicastfacility whereby a single delegate object can serve as a containerfor several other delegates, and "fan out" calls to it. SinceMicrosoft WFC components internally multicast their events (as doesSwing), there is little occasion for clients to directly combinedelegates. This feature appears to be intended to make it easier tocreate new event types and new components which multicast them. When implementing new event types in the Swing toolkit, a componentauthor may use the Moreover, the cost model for multicasting in a program written in theunadulterated Java language is easier to understand and (if necessary) modify.For example, each additional listener in a Swing component occupiesexactly two additional words, and a component with no listeners usesno storage for the absent listeners. Instead of a one-size-fits-allmulticast mechanism, Swing designers and extenders are free to usewhichever data structure best fits the application. Looking "under the hood," it is easy to understand our conclusion that anyimplementation of bound method references will either be inefficientor non-portable. A portable implementation of delegates that generates code capable ofrunning on any compliant implementation of the Java platform wouldhave to rely on the standard Java Core Reflection API. Everybound method reference would then include an embedded object of type Thus, every call to a delegate of type Of course, a VM and its JIT could recognize these uses of reflectiveoperations as special cases and inline away the allocations. However,the engineering effort required to implement such clever optimizationsis much better spent making all kinds of objects faster and lighter.It is at this point that an aesthetic objection to adding redundantfeatures to the language design solidifies into a real-world productengineering issue. In the most extreme case, a compiler and VM might avoid reflectionaltogether in favor of special native methods.While a highly efficient implementation is achievable in this way,such a strategy immediately precludes portability to compliantimplementations of the Java platform. This is a serious objection,as it abandons the core value proposition of the Java platform:"Write once, run anywhere." The proponents of bound method references have made much of theproliferation of classes that are created when adapter classes are usedextensively. They claim that these large numbers of classesthreaten an excessive enlargement of the application footprint.In evaluating these claims, it is important to understand that adapterclasses are not inherently costly. The code for the methods withinthese classes would be needed even if method references were used.The cost increment is almost entirely due to overhead imposed by aclass file format that was designed prior to the introduction of innerclasses. As a result, much information is replicated for each innerclass that could in principle be shared. For example, the classes under the package Sun chose to implement inner classes in a manner that wascompatible with the existing VM. This preserved the investmentthat our licensees and their customers have made in Java technology.However, the Java platform is still evolving. From the very introductionof inner classes, Sun has considered eventual extensions tothe It is also important to note that the in-memory footprint of anapplication is not constrained by compatibility considerations. A VMis free to introduce alternative in-memory representations, asexemplified by the on-the-fly translation to machine code performed bycurrent high-performance VMs.Newer versions of Sun's VM share information between constant pools,so that the total size of the class files, "flattened" as they are,is a misleading indicator of memory footprint. It is clear, then, that efforts toreduce application footprint are best directed toward creating evenmore efficient Java VMs, not changing the language. Suchimprovements will benefit all programs, not only those making use ofdelegation, and will do so without compromising the simplicity andelegance of the Java programming language. Many of the advantages claimed for Visual J++ delegates -- typesafety, object orientation, and ease of component interconnection --are simply consequences of the security or flexibility of the Javaobject model. These advantages are routinely enjoyed by allprogrammers using the Java language, without resorting to non-standardlanguage syntax or platform-specific VM extensions. Bound method references are simply unnecessary. They are not partof the Java programming language, and are thus not accepted bycompliant compilers. Moreover, they detract from the simplicity andunity of the Java language. Bound method references are not theright path for future language evolution. | |||||||||||||
![]() | ![]() | ||||||||||||
Oracle is reviewing the Sun product roadmap and will provide guidance to customers in accordance with Oracle's standard product communication policies. Any resulting features and timing of release of such features as determined by Oracle's review of roadmaps, are at the sole discretion of Oracle. All product roadmap information, whether communicated by Sun Microsystems or by Oracle, does not represent a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. It is intended for information purposes only, and may not be incorporated into any contract.
| ||||||||||||