| Summary: | [1.7][quick fix] Suggest to use <> where applicable | ||||||
|---|---|---|---|---|---|---|---|
| Product: | [Eclipse Project] JDT | Reporter: | Dani Megert <daniel_megert> | ||||
| Component: | UI | Assignee: | Deepak Azad <deepakazad> | ||||
| Status: | VERIFIED FIXED | QA Contact: | |||||
| Severity: | enhancement | ||||||
| Priority: | P2 | CC: | amj87.iitr, curtis.windatt.public, deepakazad, loskutov, markus.kell.r, satyam.kandula, srikanth_sankaran | ||||
| Version: | 3.7 | Flags: | markus.kell.r:
review+
|
||||
| Target Milestone: | 3.7.1 | ||||||
| Hardware: | All | ||||||
| OS: | All | ||||||
| Whiteboard: | |||||||
| Bug Depends on: | 340747, 351934 | ||||||
| Bug Blocks: | |||||||
| Attachments: |
|
||||||
|
Description
Dani Megert
This is not trivial, a few examples where the type of the created object changes or a compilation error occurs if the explicit type parameters are removed.
-------------------------------------------------------------------------
package p;
class A {}
class B extends A {}
public class X<T> {
X() {}
X(T s) {}
X<? extends A> f1 = new X<A>(); // ok to remove
X<? extends A> f2 = new X<B>(); // NOT ok to remove
X<? extends A> f3 = new X<A>(new B()); // NOT ok to remove
X<? super B> f4 = new X<A>(); // NOT ok to remove
X<? super B> f5 = new X<B>(); // ok to remove
X<? super A> f6 = new X<A>(new B()); // NOT ok to remove
X<? super B> f7 = new X<A>(new B()); // NOT ok to remove
X<? super B> f8 = new X<A>(new A()); // ok to remove
X<?> f9 = new X<A>(new B()); // NOT ok to remove
}
------------------------------------------------------------------------
Probably a good solution would be to NOT offer the quick assist if the LHS contains wildcards, as in these cases the code would be more readable if explicit type arguments are present on the RHS.
Satyam pointed out this morning that the type information is used only at compile time, and is missing at run time. Hence if the compiler does not complain, it might be ok to remove the type arguments. Having said that I am not comfortable with the idea of silently changing the type bindings. (In reply to comment #1) > X<? super A> f6 = new X<A>(new B()); // NOT ok to remove In this case removing the type arguments from RHS results in a compile error, in all other cases from comment 1 only the type bindings change. See also bug 340747 Srikanth, Assuming that replacing the type arguments with <> doesn't result into a compile error, is it safe to assume that there is no semantic change? (In reply to comment #4) > Srikanth, > Assuming that replacing the type arguments with <> doesn't result into a > compile error, is it safe to assume that there is no semantic change? No, it is not. Here is a test case that shows program output differing (no compilation error) when type arguments are replaced with <>: (this is a slightly modified version of org.eclipse.jdt.core.tests.compiler.regression.GenericsRegressionTest_1_7.test007()) public class X<T> { T field1; public X(T param){ field1 = param; } public static void main(String[] args) { X.testFunction(new X<Object>("hello").getField()); //prints 2 X.testFunction(new X<>("hello").getField()); // prints 1 } public static void testFunction(String param){ System.out.println(1); } public static void testFunction(Object param){ System.out.println(2); } public T getField(){ return field1; } } So eliding the <Object> to <> will change the program behavior while still resulting in a valid program. Which is why as https://bugs.eclipse.org/bugs/show_bug.cgi?id=340747#c3 points out such eliding can be undertaken only after first inferring and confirming that compiler's inferred type would match the explicit type provided by the programmer. (In reply to comment #1) > Probably a good solution would be to NOT offer the quick assist if the LHS > contains wildcards, as in these cases the code would be more readable if > explicit type arguments are present on the RHS. Per comment#5 of current bug and also bug 340747 comment c3, there are some tricky issues even when wildcards are not in the picture. Thanks Srikanth! The example from comment 5 provides greater clarity. Essentially in "new X<A>(new B())" if A is supertype of B, the type arguments cannot be removed. (This construct is present in 3 cases from comment 1) A cleanup, IMHO, is not a very good option here. Java7's motivation of providing the diamond construct is to make sure that the user can avoid "writing" repeatedly, the type args, or omitting them where they aren't really needed. The need for diamond ends here, and does not give any particular benefit to the user to clean up the explicit type arg declaration when they're already present in the code. Even prior to 1.7, we could elide type args for a generic method call, but we never had either a clean up or a quick fix for it. Then why now? As we can see in examples above, it is much more obvious to a reader of the code what type is actually used when type args are explicitly specified. Diamond is a rather confusing construct, where a reader will have to summon up some blood and gather some grey cells to sit and manually decipher the inferred type args. Bug 351048 may be a step towards making that simpler. Once that is done, we can just propose a quick fix for every generic type allocation expression, and the user can inspect the inferred type now when the type args have been deleted. If there's a mismatch, CTRL+Z to the rescue! (In reply to comment #8) > A cleanup, IMHO, is not a very good option here. Java7's motivation of > providing the diamond construct is to make sure that the user can avoid > "writing" repeatedly, the type args, or omitting them where they aren't really > needed. The need for diamond ends here, and does not give any particular > benefit to the user to clean up the explicit type arg declaration when they're > already present in the code. - Content assist helps you with 'writing' new code, so you do not really have to write the type arguments - 'Reading' code is an important activity which could become easier in many cases with use of diamond. I agree that there are cases where it is better to have explicit type arguments, but these are rare. For a majority of cases I think it is better to use diamond. We shouldn't start doing expensive what-if analyses in quick assists / clean ups. Waiting for bug 340747. Nevertheless, I disagree with comment 8. The only reason for adding the diamond feature to Java 7 was to make the uninteresting code bloat go away. We should support that goal as well as we can. Yes, there are cases where the compiler behavior may be hard to understand, but in the majority of practical cases, the type arguments just don't matter. (In reply to comment #10) > We shouldn't start doing expensive what-if analyses in quick assists / clean > ups. Waiting for bug 340747. If after due consideration, the UI team feels a strong need for this, please feel free to reopen bug 340747 -- Thanks. We should start with a quick fix for BETA_JAVA7 and defer the cleanup to 3.8 (too risky at this point, since the new warning hasn't been widely tested). A quick assist would need to create another AST where the compiler option is enabled. We could do that for 3.8, but only after a few cheap checks to narrow down the cases where the second AST is needed. Also, the second AST should use a focal position then. Created attachment 199569 [details]
fix + tests
Fixed in BETA_JAVA7. What's up with the fully-qualified org.eclipse.jdt.core.dom.ParameterizedType references? (In reply to comment #15) > What's up with the fully-qualified org.eclipse.jdt.core.dom.ParameterizedType > references? Looks like I need some coffee. I was thrown off by *java.lang*.reflect.ParameterizedType. Anyway, fixed it now. The quick fix does not work correctly for the following
ArrayList<Map<String, PriorityBlockingQueue<Integer>>> l2=
new ArrayList<Map<String,PriorityBlockingQueue<Integer>>>();
Bug 352699 takes care of problem mentioned in comment 17. I have added 2 more tests to LocalCorrectionsQuickFixTest17. Verified in I20110729-1200 and M20110729-1400. (In reply to comment #12) > We should start with a quick fix for BETA_JAVA7 and defer the cleanup to 3.8 > (too risky at this point, since the new warning hasn't been widely tested). I've created bug 392040 for this. Pushed branch - http://git.eclipse.org/c/jdt/eclipse.jdt.ui.git/log/?h=dazad/bug-351956-Suggest-to-use-diamond-where-applicable I added the cleanups to Unnecessary Code tab, but that can be changed easily if required. (In reply to Deepak Azad from comment #21) Oops.. wrong bug. |