PROPOSAL: Method and Field Literals
Rémi Forax
forax at univ-mlv.fr
Tue Mar 10 22:54:32 PDT 2009
Neal Gafter a écrit :
> This seems like a fairly simple change for a longstanding pain point.
> Besides moving errors from runtime to compile-time, I expect IDEs will start
> offering autocompletion.
>
> I have one small concern regarding the lookup rules for the name before the
> "#". I would expect the name before the "#" to be resolved the same way as
> the name before a "." in a normal method invocation: first look for a
> variable and then a type. But this proposal resolves it only as a type.
> Therefore, one could construct a puzzler where A#f() finds one method but
> invoking A.f() invokes another. The same puzzler could turn into a language
> wart if we ever generalize this to method references compatible with
> closures (see Stephen Colebourne's FCM proposal). Addressing this is easy:
> do the lookup the same way as it is done for normal overload resolution with
> ".", but require an error if the qualifier is not a type. As a practical
> matter, naming conventions would make it hard to tell the difference, but
> the result is one less puzzler in the language.
>
> -Neal
>
The major pain point of this proposal is, in my opinion, to have a concensus
on the type of field#fieldame and type#methodName().
The proposal uses java.lang.reflect.Field and java.lang.reflect.Method,
I would prefer java.lang.reflect.Property and java.dyn.MethodHandle.
(with java.lang.reflect.Property a pair of method handles (getter/setter)).
Rémi
> On Tue, Mar 10, 2009 at 7:49 PM, Jesse Wilson <jesse at swank.ca> wrote:
>
>
>> Rich text (preferred) here:
>> http://docs.google.com/View?docID=dhfm3hw2_62dxg677jn
>>
>> Proposal: Method and Field Literals
>>
>> AUTHOR(S):
>> Jesse Wilson
>>
>> OVERVIEW
>>
>> FEATURE SUMMARY:
>> Add syntax for method and field literals. Enables compile-time
>> checking of member references and avoids an impossible checked
>> exception.
>>
>> MAJOR ADVANTAGE:
>> The Java language neatly balances dynamic behaviour with type safety.
>> Many Java frameworks are successful because they leverage this
>> balance. Class literals like ArrayList.class are popular because of
>> the powerful APIs they enable.
>>
>> Unfortunately methods and fields are missing literal syntax. As a
>> consequence, code that reflects on a specific method or field is
>> significantly more clumsy. The member must be referenced using a
>> String, which hinders refactoring. Code that looks up specific members
>> must cope with a checked exception that will never be thrown.
>>
>> Adding literals for method and fields allows the compiler to catch
>> typos earlier. IDEs will be able to find and fix member references
>> that were previously obscured by Strings. Finally, it reduces the
>> amount of boilerplate code to create and use frameworks.
>>
>> MAJOR DISADVANTAGE:
>> Like annotations and generics, member literals can be abused.
>> Excessive use of reflection makes applications more difficult to
>> maintain, and this proposal encourages reflection.
>>
>> The member literal syntax is easily confused with regular
>> dereferencing syntax, which can be a source of confusion.
>>
>> ALTERNATIVES:
>> Frameworks like EasyMock[1] obtain method references via invocation.
>> Users invoke a factory method to construct a dynamic proxy, and invoke
>> methods on that proxy to reference them. This approach is full of
>> compromises and doesn't support fields, static methods, or final
>> classes.
>>
>> One can lookup methods using an identifying annotation. This requires
>> a possibly-unwanted layer of indirection, and it cannot be used with
>> third-party code.
>>
>> One can obtain a method reference via its String name.
>>
>> Instead of method and field literals it may be desirable to add
>> property support to the JDK. This proposal does not preclude that.
>>
>> EXAMPLES:
>>
>> BEFORE:
>> Method get;
>> Method set;
>> try {
>> get = List.class.getMethod("get");
>> set = List.class.getMethod("set", Object.class);
>> } catch (NoSuchMethodException e) {
>> throw new AssertionError();
>> }
>>
>> AFTER:
>> Method get = List#get();
>> Method set = List#set(Object);
>>
>> DETAILS
>>
>> SPECIFICATION:
>> The following new grammar rules are added:
>>
>> Expression:
>> MethodLiteral
>> FieldLiteral
>> ...
>>
>> MethodLiteral:
>> Typeopt # MethodName (TypeList)
>>
>> FieldLiteral:
>> Typeopt # FieldName
>>
>> TypeList:
>> Type [, TypeList]
>>
>> If the type is omitted, the literal refers to a visible member in the
>> current scope. This may be a member of the current type, of an
>> enclosing type, or a statically imported member. The rules for
>> resolution are the same as those for invocation.
>>
>> COMPILATION:
>> Each member reference would be replaced with a call to an internal
>> desugaring API method. The helper method will handle runtime
>> inheritance and visibility issues:
>>
>> public class A {
>> public void main(String[] args) {
>> Method driveMethod = Corvette#drive(Direction,Speed);
>> Field brakeField = Corvette#brake;
>> }
>> }
>>
>> would be desugared to :
>>
>> public class A {
>> public void main(String[] args) {
>> Method driveMethod = $Internal.methodLiteral(
>> A.class, Corvette.class, "drive", Direction.class, Speed.class);
>> Field brakeField = $Internal.fieldLiteral(A.class, Corvette.class,
>> "brake");
>> }
>> }
>>
>> VISIBILITY:
>> Unlike the java.lang.reflect() API, only visible methods may be
>> referenced in literals. To illustrate:
>>
>> // file A.java
>> public class A {
>> public String visible;
>> private String secret;
>> }
>>
>> // file B.java {
>> public class B {
>> private String mine;
>> private Field myField = B#mine; // ok
>> private Field visibleField = A#visible; // ok
>> private Field secretField = A#secret; // compile error, accessing a
>> private method
>> private Field nonexistentField = A#nonexistent; // compile error, no
>> such field
>> }
>>
>> The standard rules of visibility will apply: If you can invoke a
>> method, you can reference it. We will leverage the compiler's existing
>> visibility behaviour to implement this.
>>
>> INHERITANCE:
>> When a literal references a member inherited from a supertype, the
>> specific supertype method will be resolved at runtime. Although this
>> adds additional runtime cost, it ensures that literals and invocations
>> always have the same behaviour. For example, consider:
>>
>> // file Car.java
>> public class Car {
>> public void honk() {
>> System.out.println("honk");
>> }
>> }
>>
>> // file Corvette.java
>> public class Corvette extends Car {
>> }
>>
>> // file Main.java
>> public class Main {
>> public static void main(String[] args) {
>> Method honk = Corvette#honk();
>> System.out.println(honk.getDeclaringClass()); // prints "Car"
>> }
>> }
>>
>> Now change the source code for Corvette.java to override the honk()
>> method. Recompile only Corvette.java:
>>
>> // file Corvette.java
>> public class Corvette extends Car {
>> public void honk() {
>> System.out.println("beep");
>> }
>> }
>>
>> Now when we run Main.main(), it should print "Corvette" to illustrate
>> that method resolution occurs at runtime.
>>
>> STATIC DISPATCH:
>> Java method overloading uses the compile-time type of method arguments
>> to determine which method is invoked. During desugaring, the argument
>> method's types are replaced with the compile-time types of the target
>> method. This ensures that a reference and invocation always refer to
>> the same overload, even if the target method's class is recompiled.
>> For example:
>> Method removeMethod = List#remove(String)
>> is desugared to:
>> Method removeMethod = $Internal.methodLiteral(
>> A.class, List.class, "remove", Object.class);
>>
>>
>> STATIC RESOLUTION:
>> Members must be specified fully using constant types. The following is
>> not supported:
>> Class<?> argument = ...
>> Method remove = List#remove(argument);
>>
>> MODIFIERS:
>> This syntax applies equally to members with any modifier. Synthetic
>> members are not supported.
>>
>> RAW TYPES:
>> The Method and Field classes are not parameterized types. This
>> proposal does not preclude adding type parameters to these classes.
>>
>> TESTING:
>> It is necessary to test all combinations of visibility and inheritance
>> on both fields and methods. Both success and failure cases need to be
>> tested.
>>
>> LIBRARY SUPPORT:
>> It's necessary to add internal-use static methods to do runtime method
>> resolution. The existing APIs Class.getMethod() and
>> Class.getDeclaredMethod() are insufficient because they do not take
>> the caller's visibility into account.
>>
>> REFLECTIVE APIS:
>> No changes to java.lang.reflect. The unreleased javac tree API will
>> need expressions for member literals.
>>
>> OTHER CHANGES:
>> None.
>>
>> COMPATIBILITY
>>
>> BREAKING CHANGES:
>> None.
>>
>> EXISTING PROGRAMS:
>> Classes that use this feature cannot be targeted to earlier JVMs.
>>
>> DESIGN ALTERNATIVES:
>> It is tempting to also support constructor literals, but coming up
>> with an intuitive syntax is difficult. Some options:
>> #ArrayList(Collection)
>> ArrayList#(Collection)
>> ArrayList#new(Collection)
>>
>> REFERENCES
>> [1] EasyMock: http://www.easymock.org/EasyMock2_4_Documentation.html
>>
>> EXISTING BUGS:
>>
>>
>>
>
>
More information about the coin-dev
mailing list