Huston, we have a problem !

"Zdeněk Troníček" tronicek at fit.cvut.cz
Sun Mar 6 21:41:51 PST 2011


Hi,

my post is a feedback to the explanation why we need the <> syntax. I do
not express any doubts whether the diamond operator should be in JDK 7 or
not and nor I have them.
And this kind of feedback is not late, I suppose.

Z.
-- 
Zdenek Tronicek
FIT CTU in Prague


Joe Darcy napsal(a):
> Greetings.
>
> This vein of feedback is at least 18 months late:
> http://mail.openjdk.java.net/pipermail/coin-dev/2009-August/002173.html
>
> I am not going to engage in a debate over whether or not diamond should
> be in JDK 7.
>
> -Joe
>
> Zdeněk Troníček wrote:
>> My answer is here (I also post it on my blog at
>> http://tronicek.blogspot.com/2011/03/do-we-really-need-in-diamond-operator.html):
>>
>> As you may know, one of new features of upcoming Java 7 will be the
>> diamond operator. Purpose of the diamond operator is to simplify
>> instantiation of generic classes. For example, instead of
>> List<Integer> p = new ArrayList<Integer>();
>>
>> with the diamond operator we can write only
>> List<Integer> p = new ArrayList<>();
>>
>> and let compiler infer the value of type argument. Nice simplification.
>> But do we really need to write <>? Isn't new ArrayList() enough? In this
>> article, I will describe the arguments of the <> proponents and explain
>> why I think that these arguments are not very strong. However, I also
>> describe arguments why we need <>.
>>
>> In Java 1.4, we had raw types only:
>> List p = new ArrayList();
>>
>> Java 5 introduced generics:
>> List<Integer> p = new ArrayList<Integer>();
>>
>> Many types in Java API were generified and even though we can still use
>> generic types as raw types, there is no reason for this in Java 5 or
>> newer. When generics were introduced, raw types were allowed for
>> backward
>> compatibility so that we could gradually and smoothly adopt generics.
>> For
>> example, code in Java 1.4 can be combined with new generic code because
>> raw and generic types are allowed together. This is also expressed in
>> the
>> JLS (4.8 Raw Types):
>>
>> "The use of raw types is allowed only as a concession to compatibility
>> of
>> legacy code. The use of raw types in code written after the introduction
>> of genericity into the Java programming language is strongly
>> discouraged.
>> It is possible that future versions of the Java programming language
>> will
>> disallow the use of raw types."
>>
>> Now let's go back to the diamond operator and ask again: "Do we really
>> need <>?". The proponents of the <> syntax say that we need <> to
>> preserve
>> backward compatibility. Let's look at an example from the coin-dev
>> conference:
>>
>> class Foo<X> {
>>    Foo(X x) { }
>>    Foo<X> get(X x) { return this; }
>> }
>>
>> class Test {
>>    void test() {
>>       Foo<?> f1 = new Foo(1).get(""); //ok - can pass String where
>> Object
>> is expected
>>       Foo<?> f2 = new Foo<>(1).get(""); //fail - cannot pass String
>> where
>> Integer is expected
>>    }
>> }
>>
>> This shows the difference between new Foo(1) and new Foo<>(1). Clearly,
>> these two are different and if we changed the semantics of new Foo(1),
>> it
>> would break backward compatibility. But wait. Backward compatibility
>> with
>> what? Isn't line
>> Foo<?> f1 = new Foo(1).get("");
>>
>> a little suspicious? It uses generic type in the left part and raw type
>> in
>> the right part. Although it is legal, it is probably either omission or
>> malpractice. And its legality is probably only a side effect of "a
>> concession to compatibility of legacy code".
>>
>> Let's go further and look at another example from the coin-dev
>> conference.
>> It shows the difference between raw type and parameterized type with the
>> diamond:
>>
>> public class X<T> {
>>    public X(T t) { }
>>    public T get() { return null; }
>>
>>    public static int f(String s) { return 1; }
>>    public static int f(Object o) { return 2; }
>>
>>    public static void main(String[] args) {
>>       System.out.println(f(new X<>("").get()));
>>       System.out.println(f(new X("").get()));
>>    }
>> }
>>
>> Let's play with the code a bit. Let's assume that there was a library
>> with
>> the X class:
>>
>> public class X {
>>    public X(Object o) { }
>>    public Object get() { return null; }
>> }
>>
>> and some code that compiled against this library:
>>
>> public class Client {
>>    static int f(String s) { return 1; }
>>    static int f(Object o) { return 2; }
>>
>>    public static void main(String[] args) {
>>       System.out.println(f(new X("").get()));
>>    }
>> }
>>
>> Then, the library was generified:
>>
>> public class X<T> {
>>    public X(T t) { }
>>    public T get() { return null; }
>> }
>>
>> and we compiled the client project against the generified version. Now,
>> if
>> we changed the semantics of new X("") to new X<String>("") (or new
>> X<>("")
>> with the diamond syntax), the code would behave differently. So, the
>> answer to the title question is 'yes'. If we want to stay backward
>> compatible, we need <> and we cannot put new X("") semantically equal to
>> new X<>("").
>>
>> Another questions are how long can Java evolve and remain compatible
>> with
>> concessions to compatibility and whether newcomers to Java will
>> appreciate
>> this.
>>
>> Z.
>>
>
>




More information about the coin-dev mailing list