PROPOSAL: Static Methods in Interfaces (v1.1)
Neal Gafter
neal at gafter.com
Tue Mar 17 19:05:55 PDT 2009
Experience with extension methods have shown them to be a powerful and
more flexible alternative to this. I believe extension methods are
also simpler. If there is enough interest I could write it up.
On Tue, Mar 17, 2009 at 6:59 PM, Reinier Zwitserloot
<reinier at zwitserloot.com> wrote:
> Includes Joe D'Arcy's suggestions. An easier to read copy with markup
> is available at:
>
> http://tinyurl.com/static-methods-in-interfaces
>
>
> The text below is identical aside from the formatting:
>
>
> PROPOSAL: Static Methods in Interfaces
>
>
> VERSION
>
> This is version 1.1.
> The latest version can be found at
> http://tinyurl.com/static-methods-in-interfaces
>
>
> Changes from v1.0 to v1.1: Added links to bug reports on
> bugs.sun.com, expanded on alternatives, simplified reflective APIs,
> added note on javadoc. (via Joe D'Arcy).
>
>
> AUTHOR(S):
>
> Reinier Zwitserloot
> Roel Spilker
>
>
> OVERVIEW
>
> *FEATURE SUMMARY:*
>
>
> Static methods are now allowed in interfaces. The static method
> is defined with a method body in the interface and it exists in
> the namespace of the interface; it does not imply that
> implementing classes must implement the method. This feature is
> especially useful for utility methods that belong with a given
> interface. For example, many methods in java.util.Collections
> are specific for a particular interface, such as sort
> (java.util.List) and unmodifiableMap (java.util.Map).
>
>
> MAJOR ADVANTAGE:
>
> Allows maintaining code that 'goes together' in a single file,
> and helps auto-complete dialogs come up with more relevant
> operations on any given object. Also improves syntax by using a
> more specific term (e.g. List) instead of a usually somewhat
> generic grab bag utility class (e.g. Collections). Also allows
> interfaces to contain pseudo-constructor, for common tasks and
> default implementations (e.g. java.io.FileFilter could
> contain a
> method to create a new one based on a file extension). This
> proposal will also offer an easy solution to the current
> deplorable situation that you need to call on 2 separate
> utility
> classes, one of which has no relation to List whatsoever, just
> to create an immutable List:
> Collections.unmodifiableList(Arrays.asList(items)) can be
> replaced with the much more elegant List.of(items)
>
>
> MAJOR BENEFIT:
>
> Java (the language) is very strictly namespaced; the default
> package is discouraged and java does not allow dynamically
> adding or changing methods at runtime (so called monkey
> patching). Java also does not support mixins nor multiple
> inheritance. Therefore, the platform currently lacks a way to
> meaningfully offer utility methods for interfaces. Instead,
> kludges such as java.util.Collections exist as a vehicle for
> these support methods. Furthermore, static methods in
> interfaces
> are currently illegal (see JLS Chapter 9.4
> <http://java.sun.com/docs/books/jls/third_edition/html/interfaces.html#9.4
> >)
> so this proposed change does not complicate the language very
> much.
>
>
> MAJOR DISADVANTAGE:
>
> Confusion about the notion that static methods in java in java
> are not 'virtual' (they are not inherited and cannot be
> overridden) may cause a programmer to erroneously think a
> static
> method in an interface implies it is something an implementing
> class must implement. However, the mandatory method body should
> help avoid confusion. Slightly more complex language
> specification. No opportunity to use the static keyword in
> interfaces for some sort of /factory interface/ concept (an
> interface for constructors and static methods). The proposed
> implementation is also somewhat inconsistent in rare cases
> compared to static methods in classes. While this inconsistency
> is a disadvantage, the authors do not believe there's a way to
> avoid this inconsistency without creating more serious
> disadvantages
>
> ALTERNATIVES:
>
> The usual solution to this problem right now is to offer a
> separate utility class (a class that is not instantiable and
> contains only static methods) that contain the utility methods,
> along with a reference in the /javadoc/ of the interface to
> this
> utility class. For example, java.util.Collections is the
> utility
> class that goes with Map, List, Set and other Java Collections
> API interfaces. The use case of default / common
> implementations
> is currently handled by having an implementing class with a
> constructor. For example, a new class called
> java.io.ExtensionFileFilter could be made that takes a String
> and implements FileFilter. The sugar employed by this proposal
> is itself also an alternative: Creating a member type class
> that
> contains the static methods (With just a backwards and
> migration
> compatible API addition, you could make List.Utils.of(items)
> work in java 1.6 notation (The Utils class is an inner member
> type to the interface, which is legal, and as it is a class,
> may
> contain static methods.
>
> Another language change that can serve as an alternative is
> extension methods (the ability to lexically 'monkey patch'
> methods onto types, such as "import static
> java.util.Collections.sort into java.util.List;"
>
>
> EXAMPLES
>
>
> SIMPLE EXAMPLE:
>
> public interface Foo {
> public static void printHello() {
> System.out.println("Hello, World!");
> }
> }
>
> Foo.printHello(); //Prints 'Hello, World!
>
>
> ADVANCED EXAMPLE:
>
> package java.util;
>
> public interface List<E> extends Collection<E> {
> int size();
> // List's other instance methods
>
> public static <T> List<T> of(final T... items) {
> return new AbstractList<T>() {
> public T get(int index) {
> return items[index];
> }
>
> public int size() {
> return items.length;
> }
> };
> }
> }
>
> List<String> list = List.of("foo", "bar");
> assert list.get(0).equals("foo");
> assert list.size() == 2;
>
>
> DETAILS
>
> SPECIFICATION:
>
> Java Language Specification changes:
>
> JLS Chapter 9.1.4
> <http://java.sun.com/docs/books/jls/third_edition/html/interfaces.html#9.1.4
> >:
> original:
>
> InterfaceMemberDeclaration:
> ConstantDeclaration
> AbstractMethodDeclaration
> ClassDeclaration
> InterfaceDeclaration
> ;
>
> replacement:
>
> InterfaceMemberDeclaration:
> ConstantDeclaration
> AbstractMethodDeclaration
> StaticMethodDeclaration
> ClassDeclaration
> InterfaceDeclaration
> ;
>
>
> JLS Chapter 9.4
> <http://java.sun.com/docs/books/jls/third_edition/html/interfaces.html#9.4
> >:
> original:
>
> Every method declaration in the body of an interface is
> implicitly abstract, so its body is always represented by a
> semicolon, not a block.
>
> replacement:
>
> Every non-static method declaration in the body of an
> interface is implicitly abstract, so its body is always
> represented by a semicolon, not a block.
>
> original:
>
> Note that a method declarated in an interface must not be
> declared static, or a compile-time error occurs, because
> static methods cannot be abstract.
>
> replacement:
>
> None - this line is removed from the JLS.
>
>
> JLS Chapter 9.5
> <http://java.sun.com/docs/books/jls/third_edition/html/interfaces.html#9.5
> > and
> 9.6
> <http://java.sun.com/docs/books/jls/third_edition/html/interfaces.html#9.6
> >
> are bumped to 9.6 and 9.7, respectively, and a new 9.5 is
> added:
>
> ------------------------------------------------------------------------
>
>
> 9.5 Static Method Declarations
>
> StaticMethodDeclaration:
> StaticMethodModifiers TypeParameters_opt ResultType
> MethodDeclarator Throws(opt) ;
>
> StaticMethodModifiers:
> static
> MethodModifiers static
> static MethodModifiers
>
> The MethodModifiers are described in 8.4.3
> <http://java.sun.com/docs/books/jls/third_edition/html/classes.html#78188
> >,
> The access modifier |public| is discussed in 6.6
> <http://java.sun.com/docs/books/jls/third_edition/html/names.html#104285
> >.
> A compile-time error occurs if the same modifier appears more
> than once in an static method declaration. The static keyword
> is
> mandatory.
>
>
> Static method declarations in interfaces are either public
> or private; protected and package private are not allowed.
> If no access modifier is specified, the static method is
> implicitly public, to be consistent with the notion that
> everything else in an interface, be it a field, an abstract
> method, or a member type, is implicitly public. Private
> static methods are allowed to accommodate helper
> methods. Other than being limited to public and private
> access, a static interface method is identical to a method
> declaration in a class (8.4)
> <http://java.sun.com/docs/books/jls/third_edition/html/classes.html#40420
> >.
> During compilation, all static methods are stored in a
> synthetic inner class called $Methods, which is generated
> with a private constructor. If that class already exists in
> the source file, a compile-time error occurs.
>
>
> ------------------------------------------------------------------------
>
> JLS Chapter 15.12.1
> <http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.12.1
> >:
>
> The specification of method invocation forms that invoke static
> methods are updated to refer to 'class or interface' instead of
> just 'class', and the following line:
>
> If /TypeName/ is the name of an interface rather than a
> class, then a compile-time error occurs, because this form
> can invoke only |static| methods and interfaces have
> no |static| methods.
>
>
> is replaced with:
>
> If /TypeName/ is the name of an interface rather than a
> class, then the call is presumed to be for a static method
> in a synthetic member class of the interface, called
> $Methods. If the method exists, the class to be searched is
> denoted by /TypeName.$Methods/ where /$Methods/ is a static
> inner class of the interface /TypeName/, literally called
> "$Methods".
>
>
> COMPILATION:
>
> Any interface with static methods is sugared by creating a
> member class called $Methods which will contain the static
> methods. The generated $Methods class should also have a
> private
> constructor, as they aren't supposed to be instantiable. If the
> $Methods inner class has been explicitly created in the source
> file, any static methods in the interface are considered a
> compile-time error (if the class is present in the source file,
> the assumption is that the programmer wants to keep manual
> control of the static methods). For method invocations,
> currently, an invocation of the form InterfaceName.method(),
> will result in an immediate compile error. The compiler will
> instead need to search the $Methods class (if any exists) for
> the method, and rewrite the call to
> InterfaceName.$Methods.method() if the method does exist in the
> $Methods inner class.
>
> The method is not inherited by any member types. So, the second
> 'hello()' call in the following example would result in a
> compile time error (method not found):
>
> public interface Foo {
> public static void hello() {
> System.out.println("Hello, World!");
> }
> }
>
> public class Bar implements Foo {}
>
> Foo.hello(); //works
> Bar.hello(); //does not work
>
>
> This is an unfortunate inconsistency (if Foo was a class,
> Bar.hello() would work just fine), but there is no way to
> adequately recreate this inheritance system with syntax sugar.
> Even with a more thorough solution (that involves changing the
> JVM), allowing inheritance of the methods would mean allowing
> diamond relations (where 1 class implements 2 interfaces, that
> each have the same static method signature with different
> implementations. Which one is chosen?). This is principally the
> reason why this proposal suggests not letting the method be
> inherited. However, if inheritance is deemed important, the
> alternate solution is to fix the JVM Specification chapter 2.13
> <http://java.sun.com/docs/books/jvms/second_edition/html/Concepts.doc.html#16432
> > in
> similar ways as the JLS, and make static methods legal in
> interfaces. The Type.method() invocation would then require a
> much broader search and should give up with a compile-time
> error
> if a diamond relation is found, listing the conflicting
> implementations and asking the programmer to choose one.
>
> As this proposal breaks the norm on inheritance already, the
> following syntax is not allowed either, which for static
> methods
> in classes *is* currently legal but flagged as a warning in all
> popular IDEs and code style checkers:
>
> Character c = 'f';
> c.isWhiteSpace(' '); //if Character was an interface, this
> would not be legal.
>
>
>
> TESTING:
>
> This new feature can be tested by applying the existing tests
> for static method calls to static methods in interfaces.
> Compilation and class file parsing needs to be expanded to
> apply
> tests to read method bodies in interfaces as well as classes.
> "Finding" the static method inside the $Methods inner class
> during compilation needs to be tested, which is straight
> forward. The changes described below to the reflective APIs
> also
> need testing, which is also straight forward.
>
>
> LIBRARY SUPPORT:
>
> No library support is needed. However, it would be advisable to
> update various interfaces in the core java APIs with useful
> static utility methods. Some examples:
>
> * java.util.List/Map/Set: All methods in
> java.util.Collections should also be made available on
> the
> appropriate java collections API interface.
> * java.io.Closeable: should contain a utility method
> 'closeAndIgnoreException' (arguably better suited on
> InputStream instead).
> * java.util.List/Set: Should contain an 'of' method that
> makes unmodifiable lists and sets via varargs.
> * java.io.FileFilter: Should contain an
> 'ofExtension(String)' method that creates a FileFilter
> for
> the provided extension.
>
>
> REFLECTIVE APIS:
>
> Currently, synthetic members are not treated specially by the
> reflection API. Therefore, this proposal does not require any
> reflective API changes. Attempting to use reflection to access
> these methods requires you to access them via the generated
> $Methods member. Asking for such a method's parent class would
> return the $Methods class, not the interface.
>
>
> OTHER CHANGES:
>
> The javadoc tool will need a minor change: It will need to
> produce a new section on static methods for interfaces, if they
> exist. (Unlike reflection, javadoc should abstract away the
> inner $Methods class). Fortunately, this code already exists
> for
> printing static methods in normal classes.
>
>
> MIGRATION:
>
> No migration is needed. However, any java projects that
> currently employ utility classes (defined as having a private
> constructor that is not called anywhere in scope) which either
> return interface types, or take as first parameter an interface
> type, or both, where all previously mentioned interfaces are in
> the same package, are likely candidates for moving or copying
> to
> the relevant interface. Thus, IDEs can offer refactor advice to
> perform this task automatically and to find likely candidates.
> Such a refactor tool would for example identify all methods in
> java.util.Collections.
>
>
> COMPATIBILITY
>
> BREAKING CHANGES:
>
> Existing source that already uses an inner type named $Methods
> in an interface will change semantics when this proposal is
> implemented, primarily when queried via reflection. Between the
> vanishingly small odds of both a $Methods already existing and
> its methods being queried by the reflection API, and the
> general
> rule that $ should only be used in type names by compilers, the
> potential breaking change is hardly worth mentioning.
>
>
> EXISTING PROGRAMS:
>
> Existing programs are not affected by this change, other than
> as
> described above in the 'breaking changes' section.
>
>
> REFERENCES
>
> EXISTING BUGS:
>
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4093687
> (Main RFE)
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4291381
> (Duplicate)
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4491759
> (Duplicate)
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4306573
> (Duplicate)
>
>
> URL FOR PROTOTYPE (optional):
>
> None.
>
>
>
>
>
More information about the coin-dev
mailing list