PROPOSAL: Named method parameters

Joseph D. Darcy Joe.Darcy at Sun.COM
Tue Apr 21 08:36:07 PDT 2009


Catching up on responses, as has been further discussed on the list 
recently, requests in this general vein have been considered before in 
JDK 6.  While there are certainly use-cases this facility could clarify, 
I remain unconvinced of the cost/benefit ratio of this proposal.

A few design notes, a single @PublicParameterNames annotation with a 
boolean member could be used instead of a pair of "do it/don't do it" 
annotations.

A full proposal for this facility would need to deal with the cases 
where the number of parameters in the class file differs from the number 
of parameters in the source code, a situation already mildly exposed 
when calling toGenericString on some Method and Constructor objects.

Not supporting parameter reordering greatly simplifies the proposal by 
leaving method selection largely unaffected, but also seems to limit the 
usefulness of the proposal.  If the main benefit is just seeing the 
parameter name in the program text; can't the IDE do that?

I'd isn't clear to me how @PublicParameterNames would interact with 
overridden methods in class hierarchies.  Presumably the names of the 
static type of the call site would need be match, even though the 
runtime type could differ.  If a subclass overrode a method and changed 
its parameter names (which currently has no affect on compatibility), 
the subclass would no longer be substitutable for the parent class, 
which would break a fundamental design principle.

At least there is no binary compatibility impact since the names would 
only be checked at compile time and binary compatibility is about 
preserving the ability to link.

-Joe

Paul Martin wrote:
> I'd like to propose the implementation of optionally named method
> parameters, and suggest that they are particularly useful when creating
> immutable objects (which are important in our increasingly concurrent
> world).
>
> Note that this is a topic that seems to have been considered before (see the
> note in http://paulhammant.com/blog/announcing_paranamer.html which suggests
> that it was even considered for Java 6), but I can't see it in the current
> list of Java 7 changes or in the Project Coin mailing list archives (though
> others have also discussed it in relation to Java 7, such as Alex Miller in
> http://tech.puredanger.com/2007/08/15/dr-java7/ and
> http://tech.puredanger.com/2007/10/11/java7-roundup-32/).  Therefore I am
> proposing it here - I think that it is an important change (unless anyone
> can suggest how I can reasonably create an immutable object with four or
> more properties without using a Builder or a list of unnamed parameters).
>
> Also note that other relevant references include:
> http://blogs.sun.com/abuckley/entry/named_parameters (which discusses why
> parameter reordering might be difficult),
> http://beust.com/weblog/archives/000096.html (which suggests that we do not
> need named parameters, but really just shows the use of the Builder pattern
> which has limitations).
>
>
> Named method parameters
>
> AUTHOR(S):
>
> Paul Martin
>
> OVERVIEW
>
> FEATURE SUMMARY:
>
> Named parameters allow a method or constructor caller to explicitly state
> the parameter name of each parameter value passed to the method or
> constructor.  Without named parameters, only the order of the parameter
> values is significant (and it may not be clear what each value represents).
>
> MAJOR ADVANTAGE:
>
> This is a relatively simple way of introducing named parameters to the Java
> platform.
>
> MAJOR BENEFIT:
>
> Named parameters allow method calls with relatively long lists of parameters
> (greater than 3) to be understood by developers.  This can also facilitate
> the direct use of constructors and factory methods to create immutable
> objects, where otherwise Builders or mutable JavaBeans would be required.
>
> MAJOR DISADVANTAGE:
>
> The syntax for method calls would change to allow both named and unnamed
> parameters to be used.
>
> Named parameters might be used too often, which could unnecessarily clutter
> source files.
>
> Metadata to store the names of the parameters must be added to classfiles
> (for example as annotations).
>
> The use of annotations to describe named parameters would mean that no
> metadata would be stored about the parameter names used by the method
> caller, and so no runtime checks to match the parameter names being used
> could be made (only compile-time).  If the parameter names change (but
> otherwise the method signature does not), then the method caller would not
> be aware of the changes until it was recompiled.  Note that this is existing
> behaviour for unnamed parameters, and would only be a problem if the meaning
> of the parameters also changes (which should indicate that the caller would
> need to change anyway, but this would not be detected automatically at
> runtime).
>
> ALTERNATIVES:
>
> Unnamed parameters can make the same method calls as named parameters, but
> if there are many parameters they are harder to understand and prone to
> ordering-related bugs (particularly for primitive types or Strings).
>
> The Builder pattern can be used to simulate named parameters in
> constructors/factory methods.  For example the following class uses a
> Builder to initialise itself (note that only two properties are used to
> simplify the example):
>
>     public final class MyClass {
>
>         private final String name;
>         private final int age;
>
>         private MyClass(Builder b) {
>             this.name = b.name;
>             this.age = b.age;
>         }
>
>         public static class Builder {
>
>             private String name;
>             private int age;
>
>             /**
>              * Name to set.
>              */
>             public Builder setName(String name) {
>                this.name = name;
>                return this;
>             }
>
>             /**
>              * Age to set
>             */
>             public Builder setAge(int age) {
>                 this.age = age;
>                 return this;
>             }
>
>             public MyClass build() {
>                return new MyClass(this);
>             }
>         }
>     }
>
> Objects can then be constructed in the following manner:
>
>     MyClass obj = new MyClass.Builder().setName("Fred").setAge(53).build();
>
> However, the use of a builder requires additional code, and all parameters
> are effectively optional from the perspective of the compiler (it cannot
> easily check that all of the required setter methods have been called), so
> bugs may occur where parameter values are not set.  Note that runtime checks
> can be made to ensure that all property values are set, but they involve
> additional work and cannot be used by the compiler (though static analysis
> of the code in conjunction with annotations might be able to repeat many of
> these checks).
>
> There are also many ways to implement named parameters that are different to
> the solution proposed here.  These include:
>
> Implement optional named parameters on all methods:  This avoids the need
> for the @PublicParameterNames annotation, but may mean inconsistent usage of
> named parameters - the annotation is also a suggestion for the use of named
> parameters by the caller (which IDEs can also make use of).  This will also
> highlight the difference to classfiles compiled with earlier versions of
> Java, where named parameters cannot be used at all (since it will then not
> be obvious when named parameters can and cannot be used).
>
> Add parameter names to the classfile as 'fundamental' method metadata rather
> than as annotations: This may allow closer integration of the named
> parameters with the rest of the language, but its impact on the rest of the
> language (and JVM) is much greater.  The same inconsistencies and
> incompatibilities described in the previous alternative would also apply.
> In addition, the use of annotations should not preclude the subsequent
> modification of classfiles in a later release - the annotations could still
> remain (at a potential cost of some duplication).
>
> EXAMPLES
>
> SIMPLE EXAMPLE:
>
> Constructor declaration:
>
>     @PublicParameterNames
>     public MyClass(String name, int age) { ....
>
> Constructor use:
>
>     MyClass obj = new MyClass(name: "Fred", age: 53);
>
> ADVANCED EXAMPLE: Show advanced usage(s) of the feature.
>
> The full class definition from the simple example is shown below, as a
> contrast to that provided in the Builder example.
>
>     public final class MyClass {
>
>         private final String name;
>         private final int age;
>
>         /**
>          * @param name Name to set
>          * @param age Age to set
>          */
>
>         @PublicParameterNames
>         public MyClass(String name, int age) {
>             this.name = name;
>             this.age = age;
>         }
>     }
>
> DETAILS
>
> SPECIFICATION:
>
> The @PublicParameterNames annotation is used on a constructor or method to
> allow named parameters to be used when calling it.  It can also be applied
> to a class or package to apply to all methods within.  Similarly, a
> @NoParameterNames annotation can be used on a constructor, method, or class
> to override the use of @PublicParameterNames at a higher level.
>
> The compiler can then automatically generate a
> @PublicParameterName(value="parameter-name") annotation for each affected
> method.  These can then be used by the compiler (and IDE) to validate the
> parameter names used by callers of the method or constructor.
>
> The use of parameter names by callers is always optional (primarily for
> backwards compatibility).  However, parameter names cannot be used for some
> parameters and not others (this would make the code harder to read).
>
> Parameters must always be specified in the same order regardless of whether
> parameter names are used - parameter reordering by callers is not allowed
> (reordering would make overloading difficult, and is not really necessary).
>
> Inheritance: Neither the @PublicParameterNames annotation (and
> @NoParameterNames annotation), or the names of the parameters themselves,
> need to be inherited.  This is because only static evaluation of a caller's
> parameter names will be applied (rather than at runtime), so the callers
> parameter names only need to match those of the declared type of the
> target.  However, it would still be advisable to reuse the same parameter
> names and annotations when overriding a method (IDEs could help with this).
>
> COMPILATION:
>
> The compiler must automatically generate a
> @PublicParameterName(value="parameter-name") annotation for each method and
> constructor annotated with @PublicParameterNames (or whose the parent class
> or package is annotated with @PublicParameterNames and the child class or
> method does not override it with @NoParameterNames).
>
> For example:
>
>     int myMethod(int param1, String param2)
>
> Would effectively become:
>
>     int myMethod(@PublicParameterName("param1") int param1,
> @PublicParameterName("param2") String param2)
>
> Method-calling syntax would need to change, using a colon to separate the
> parameter name and value where the are used.  For example:
>
>    MyClass obj = new MyClass(name: "Fred", age: 53);
>
> When a method caller uses parameter names, the compiler must check that
> those parameter names exactly match the value of generated
> @PublicParameterName annotations of the target method or constructor.  It is
> a compilation error if they do not match or the target method or constructor
> does not have named parameters.
>
> IDEs can use the @PublicParameterNames and @NoParameterNames annotations (or
> @PublicParameterName directly) to automatically insert the relevant
> parameter names as part of code-completion.  Additional refactoring support
> would also be required to enable parameter names to be renamed, or added and
> removed completely.
>
> Frameworks such as Spring can use the same annotations to allow objects to
> be created from their configuration files using named parameters to
> constructors and factory methods.  Currently they only allow objects to be
> created from configuration files as JavaBeans (with setter methods) or with
> ordered (and unnamed) parameters.
>
> TESTING:
>
> The feature can be tested by compiling and running programs that exercise
> the feature.
>
> LIBRARY SUPPORT:
>
> No.
>
> REFLECTIVE APIS:
>
> java.lang.reflect.Method and java.lang.reflect.Constructor could be enhanced
> with new methods that return parameter names.  However, that is not required
> to successfully implement the proposal.
>
> OTHER CHANGES:
>
> No.  The use of named parameters is always optional.  The javadoc tool
> already documents parameter names.  Other tools/libraries might benefit from
> these changes, but their use is not required.
>
> MIGRATION:
>
> The @PublicParameterNames annotation (and @NoParameterNames annotation)
> simply needs to be added to the appropriate methods.  IDEs could then
> suggest the use of parameter names for the method's callers, and apply the
> changes automatically.
>
> COMPATIBILITY
>
> BREAKING CHANGES:
>
> No.
>
> EXISTING PROGRAMS:
>
> The changes required by this feature should be transparent to existing
> source and class files if annotations are used internally to describe the
> named parameters.  I am not sure what the impact would be otherwise.
>
> REFERENCES
>
> EXISTING BUGS:
>
> 4124331 (though it is set to 11-Closed, Will Not Fix, request for
> enhancement, and from 1998)
>
>   




More information about the coin-dev mailing list