PROPOSAL: Simplified Varargs Method Invocation (original) (raw)
Reinier Zwitserloot reinier at zwitserloot.com
Fri Mar 6 06:58:06 PST 2009
- Previous message: PROPOSAL: Simplified Varargs Method Invocation
- Next message: PROPOSAL: Simplified Varargs Method Invocation
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
The plot thickens. Javac v1.5 WILL warn you when you de-varargs a
superclass. However, any javac v1.6 will NOT. Evidently one of the
javac engineers had a reason to remove the warning. That reason would
probably be very pertinent to this discussion. Anyone familiar enough
with mercurial to dig the comment on this changeset out of the javac's
repository?
Remi - I covered the need to update superclasses without breaking
implementers, but if you (re)compile a subclass that de-varargses when
source compatibility mode is 1.5 or up, I can see absolutely no reason
for javac to be silent about it. It should generate this warning. That
change to javac 1.6 needs to be undone.
If, as Remi suggests, we treat warnings as effective errors, and thus
we treat generics-based arrays as something you really shouldn't ever
use, then we have an entirely different bug: The varargs mechanism is
then broken. Something as simple as this should then not be something
you ever ought to do (eventhough in practice it can't go wrong and the
warning generated by the following code snippet is a 'bug' in that
there's no way it'll ever break):
listOfLists = Arrays.asList(listA, listB);
If there is no (acceptible) way to let the compiler figure out what is
and isn't safe, then the only solution I can see is to introduce
java.lang.VarArgs, and new syntax (4 dots?), or just re-use
java.util.List.
Either way, I'm still convinced that this is effectively a javac bug,
or at the very least a severe 'feature' that has caused many tens of
thousands of manhours of solution-hunting and frustration.
For what it's worth, its my opinion that we can and should figure out
when varargs methods are perfectly safe, generate no warnings anywhere
if that happens and all involved code is compiled by javac7 or higher,
and accept that Bad Things will happen if you varargs a non-reified
type into a method where a subclass has reified the type (but that
warning should be restored). After all, Bad Things happen now too, and
in either situation you get at least 1 warning. However, in the
proposed solution, the warning is at least moved to the place where it
is more relevant: The programmer who is reifying that array type.
Granted, without an additional proposal to rewrite a signature to
Object[], there's nothing this programmer can do about it, but at
least he knows what's happening. The current warning on the call site
does absolutely nothing useful other than suggesting you can't really
use varargs at all, eventhough (quite literally) in 99%+ of all cases,
there's absolutely no danger whatsoever.
--Reinier Zwitserloot
On Mar 6, 2009, at 09:28, Rémi Forax wrote:
Reinier Zwitserloot a écrit :
Heh, that was the next proposal I was going to write.
(Apologies for a long and technically complicated post. I've rewritten it several times in an attempt to get to the point faster, but this is the best I can do). It really pains me to rain on your parade. I was doing some experimenting and found an admittedly very unlikely scenario that isn't backwards compatible. Then I realized, that this is actually (arguably) a bug, or at least a severe misfeature in javac right now! Therefore, this proposal should fix this problem as well. Of all proposals so far, I rate this one the highest, because it causes so much confusion and is closer to a bug in javac than a language feature, so I would be very happy if this proposal can be fully ironed out. Complete code showing the problem - copy and paste into Main.java, compile, and run: ------ import java.util.*; class Foo { public void foo(T... t) {} } class Bar extends Foo { //de-varargsing? Why is this legal? Because you want to be able to replace an array with a varargs in library without creating errors in code that use that library. public void foo(String[] t) { System.out.println(t.getClass().getComponentType()); } } public class Main { public static void main(String[] args) { Foo f = new Bar(); List l = Arrays.asList("a", "b", "c"); bar(f, l); } public static void bar(Foo f, List l) { f.foo(l.get(0), l.get(1), l.get(2)); } }
----- The result is an error: Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String; Right now, you get the usual varargs warning, but nothing else at compile time. At runtime, you get the above error. Warnings in Java are not like in C, it means something will go wrong :) the call: f.foo(l.get(0), l.get(1), l.get(2)); generate a warning because you are creating an arry of parameterized type (a Foo[]) which are "inherently unsafe" to quote gilad bracha. The real bug here is the ability for any subclass to de-varargs a parameter. No [...] See: 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) Rémi
- Previous message: PROPOSAL: Simplified Varargs Method Invocation
- Next message: PROPOSAL: Simplified Varargs Method Invocation
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]