PROPOSAL: Simplified Varargs Method Invocation
Bob Lee
crazybob at crazybob.org
Thu Mar 5 17:30:00 PST 2009
Simplified Varargs Method Invocation
AUTHOR: Bob Lee
*OVERVIEW
*
FEATURE SUMMARY: When a programmer tries to invoke a *varargs* (variable
arity) method with a non-reifiable varargs type, the compiler currently
generates an "unsafe operation" warning. This proposal moves the warning
from the call site to the method declaration.
MAJOR ADVANTAGE: Safely and significantly reduces the total number of
warnings reported to and suppressed by programmers. Reduces programmer
confusion. Enables API designers to use varargs.
MAJOR BENEFIT: Plugs a leaky abstraction. Creating an array when you call a
varargs method is an implementation detail that we needn't expose to users.
Addresses a well known "gotcha" encountered when you mix varargs and
generics. Most programmers are surprised to find out you can only clear this
warning by suppressing it (especially considering we introduced varargs and
generics in the same language update); they waste time looking for
alternatives that don't exist. Google Code Search finds almost 90k callers
of Arrays.asList() (http://tinyurl.com/dept4d). We could safely suppress the
warning once and for all on asList()'s declaration instead of unnecessarily
warning every caller that uses a non-reifiable type.
MAJOR DISADVANTAGE: The compiler will generate a warning for a method
declaration whether or not someone actually calls the method with a
non-reifiable type. Allows loss of type safety if the varargs method
suppresses the warning and uses the varargs array unsafely.
ALTERNATIVES:
a) Don't mix varargs with generics. Use the more verbose and less
straightforward but warning-free builder pattern. Most API designers choose
this route.
b) Improve the warning message. Current message: "uses unchecked or unsafe
operations"
c) Reify generics.
d) Introduce a second varargs syntax (perhaps using "...." instead of
"...") that uses List<T> instead of T[].
e) Defile the type system.
Note: This proposal doesn't preclude any of these other approaches.
*EXAMPLES
*
Before this change:
static <T> List<T> asList(T... elements) { ... }
static List<Callable<String>> stringFactories() {
Callable<String> a, b, c;
...
*// Warning: **"uses unchecked or unsafe operations"*
return asList(a, b, c);
}
After this change:
*// Warning: **"enables unsafe generic array creation"*
static <T> List<T> asList(T... elements) { ... }
static List<Callable<String>> stringFactories() {
Callable<String> a, b, c;
...
return asList(a, b, c);
}
If asList() prohibits storing elements that aren't of type T in the elements
array, we can safely suppress the warning:
*@SuppressWarnings("generic-varargs")
// Ensures only values of type T can be stored in elements.
* static <T> List<T> asList(T... elements) { ... }
*DETAILS
*
SPECIFICATION: When compiling code that calls a varargs method with a
non-reifiable varargs element type, if the target method was compiled
targeting Java 7 or later, the compiler needn't generate a warning for the
caller. When compiling a varargs method that could accept a non-reifiable
varargs type, the compiler should generate a warning on the varargs method
declaration. A varargs type is non-reifiable if it contains a type variable
anywhere in its signature. For a varargs argument of type T, the programmer
can safely suppress the warning using @SuppressWarnings("generic-varargs")
so long as the varargs method ensures that only elements of type T can be
stored in the varargs array.
COMPILATION: Tools should no longer generate a warning for varargs method
callers. Instead, they should generate a warning for varargs method
declarations that support non-reifiable types.
TESTING: Compile test programs and ensure that the compiler generates the
expected warnings.
LIBRARY SUPPORT: Suppress warnings on the following varargs methods in the
JDK:
- Arrays.asList(T... a)
- Collections.addAll(Collection<? super T> c, T... elements)
- EnumSet.of(E first, E... rest)
REFLECTIVE APIS: n/a
OTHER CHANGES: n/a
MIGRATION: Existing callers may be able to remove
@SuppressWarnings("unchecked") from their code. Existing libraries should
add @SuppressWarnings("generic-varargs") to methods with signatures
containing non-reifiable varargs types.
*COMPATIBILITY
*
BREAKING CHANGES: None
EXISTING PROGRAMS: If you recompile an existing program with "-target 7",
the compiler will generate warnings for method declarations containing
non-reifiable varargs types.
*REFERENCES
*
EXISTING BUGS: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6227971
JLS Section 15.12.4.2 "Evaluate Arguments" (
http://java.sun.com/docs/books/jls/third_edition/html/expressions.html)
"If the method being invoked is a variable arity method
(§8.4.1)<http://java.sun.com/docs/books/jls/third_edition/html/classes.html#38698>m,
it necessarily has n>0 formal parameters. The final formal parameter
of m
necessarily has type T[] for some T, and m is necessarily being invoked with
k0 actual argument expressions.
If m is being invoked with kn actual argument expressions, or, if m is being
invoked with k=n actual argument expressions and the type of the kth
argument expression is not assignment compatible with T[], then the argument
list (e1, ... , en-1, en, ...ek) is evaluated as if it were written as (e1,
..., en-1, new T[]{en, ..., ek}).
The argument expressions (possibly rewritten as described above) are now
evaluated to yield argument values. Each argument value corresponds to
exactly one of the method's n formal parameters."
Angelika Langer's Java Generics FAQ, "Why does the compiler sometimes issue
an unchecked warning when I invoke a 'varargs' method?" (
http://tinyurl.com/8w2dk)
Josh Bloch's "Effective Java" 2nd Edition, page 120 (
http://tinyurl.com/chtgbd)
Alex Miller's blog, "Generics puzzler - array construction" (
http://tech.puredanger.com/2007/02/27/generics-array-construction/)
"Java Generic and Collections", page 95 (http://tinyurl.com/c53pnu)
More information about the coin-dev
mailing list