From: Lew on
Roedy Green wrote:
> & is used where you would expect to use comma. extends is used where
> you would expect to use implements. super does not mean super.

I assume you're talking about something like

public class Foo
<T extends Collection<?> & Comparable<? super T>>

I don't know why you would expect a comma where '&' is used - that would be
incredibly ambiguous. Commas between type parameters represent different type
parameters, i.e., where more than one type is specified:

Map <T extends Foo, U extends Bar>

Replacing '&' in intersection types (and doesn't '&' communicate the idea of
"intersection" just perfectly?) with a comma would conflict with that usage.

Why would "implements" be better than "extends"? The supertype doesn't have
to be an interface. The idea of "extension" is much more natural for type
analysis than "implementation". Really, "implementation" is not at all a
natural concept for type analysis.

And how does "super" not mean super? The type that is "super" ('?' in the
example here) is a supertype; using "super" as the keyword seems entirely natural.

And why are we bitching about this five-year-old syntax anyway? It's a done
deal. Java already has generics defined the way Java already has generics
defined. It will be far, far more productive to learn the syntax than to try
to change it. Especially if the proposed changes are far, far less sensible
than the status quo.

--
Lew
From: Thomas Pornin on
According to Roedy Green <see_website(a)mindprod.com.invalid>:
> It just bugs me that specifying the contents of a container should be
> any more complicated that specifying the contents of an array.

Arrays in Java are simple because they have a special feature which
generics-enhanced collections do not: arrays know their element type.
When you create a String[], the array instance knows that it contains
String instances and nothing else.

This allows subtyping between array types. For instance, consider the
following:

String[] a = new String[10];
Object[] b = a;
b[0] = new Integer(42);

this code snippet compiles; in particular, the contents of 'a' are
silently converted to 'Object[]'. The third line also compiles finely
(an Integer is certainly an Object, and storing an Object reference into
an array of Object references looks fine on the face of it). Upon
execution, of course, the third line triggers an ArrayStoreException
because the array is really an array of String, not just any Object, and
the instance knows it. The store operation entails a dynamic type check.

Now, try to replace this with a List:

List<String> a = new ArrayList<String>();
List<Object> b = a;
b.set(0, new Integer(42));

this code snippet does not compile: the contents of 'a' cannot be
silently converted to the 'List<Object>' type. Why so ? Because the list
instance does NOT know it element type. Generics work by so-called 'type
erasure' which means that at the bytecode+JVM level, the instance knows
that it is 'an ArrayList', not 'an ArrayList of String'. Consequently,
the storage of an Integer into the list (in the third line) cannot
trigger an appropriate runtime exception: the list cannot enforce the
rule that it shall contain only String instances because it has no way
to know that it shall contain only String instances. Because of that,
the compiler cannot allow the silent conversion of a List<String>
into a List<Object>.

You can bypass the compiler by using a naked List type:

List<String> a = new ArrayList<String>();
List b = a;
b.set(0, new Integer(42));
System.out.println(a.get(0).length());

this code snippet compiles with a warning ('uses unchecked or unsafe
operations') because the compiler cannot ensure anymore that the
container invariant (the list contains only String instances) is
maintained. At runtime, the third line is executed without any problem,
but this breaks the invariant: the list now contains an 'Integer'. This
problem is illustrated by the fourth line: the 'get(0)' method is called
on 'a', which is a List<String>, hence it is quite natural to expect,
from the caller point of view, that a String instance is obtained, and
calling length() on a String instance should be no problem. However,
this triggers a ClassCastException. You cannot escape the JVM type
system, but here the runtime type check can be applied only when getting
values out of the list (the caller knows the type to expect, but the
list itself does not).


I am quite sure that you already know all this, but I wrote it to stress
my point: container types are intrinsically messy and complex, i.e. they
do not allow subtyping. This is a generic property which is not limited
to Java. To cope with containers in a context of subtyping, a language
type system must include some way to handle _partial_ information on the
contained type, which implies the whole armada of bounded wildcards. But
for Java arrays, the designers of Java thought that such complexity
ought to be avoided, and they could avoid it, by adding a runtime type
check upon storage. That check allows the use of arrays in much simpler
ways, with seemless integration in the Java type system.

To sum up, it is not that collections-with-generics are overly complex.
It is that Java arrays are overly simple, through the use of a trick
which needs some quite extensive support from the JVM: the JVM has to
know the arrays as being special entities, must have special access
opcodes, and must integrate the array types special properties into the
bytecode verification phase. This trickery made you believe that
interactions of types with containers are inherently simple, and that is
simply not the case.


> There does not seem to be sufficient benefit to justify all the fuss.

The benefits here are backward compatiblity: generics could be
introduced into the language while requiring only very limited extra
support from the JVM. In a way, if you want Java without the fuss
implied by backward compatibility, use C#.


--Thomas Pornin
From: Tom Anderson on
On Tue, 6 Oct 2009, Lew wrote:

> Arne Vajh?j wrote:
>> Lew wrote:
>>> Arne Vajh?j wrote:
>>>> <T> is new syntax. Just not new keywords. And it definitely added
>>>> complexity - just consider how many questions are asked about it here.
>>>
>>> It is most assuredly not new syntax. The Java version that introduced it
>>> hits end-of-service-life in less than four weeks. It was introduced over
>>> five years ago. In what IT context is five years considered "new"?
>>
>> It was new syntax when it was added.
>
> So was the "assert" keyword. So were anonymous classes. Heck, the Java
> language itself was new when it first came out. Come on.

You should write to these chaps and complain about their name:

http://www.new.ox.ac.uk/

tom

--
Model 706-8073-421, Robot Sonic
From: Patricia Shanahan on
Tom Anderson wrote:
> On Wed, 7 Oct 2009, Lew wrote:
>
>> Roedy Green wrote:
>>> & is used where you would expect to use comma. extends is used where
>>> you would expect to use implements. super does not mean super.
>>
>> Why would "implements" be better than "extends"? The supertype
>> doesn't have to be an interface. The idea of "extension" is much more
>> natural for type analysis than "implementation".
>
> The supertype also doesn't have to be a class. This:
>
> List<? extends Runnable>
>
> Is unnatural.

The "?" can represent either a class that implements Runnable or an
interface that extends it. There are a total of three cases, class
extends class, interface extends interface, and class implements
interface. "extends" is appropriate for two of the cases, and the same
keyword has to handle class implements interface and interface extends
interface, so I think "extends" is the less bad choice.

Perhaps it was a mistake to use a special keyword for introducing an
interface in a class declaration. If the superclass and all interfaces
had been introduced by "extends" the problem would not exist.

>> And how does "super" not mean super? The type that is "super" ('?' in
>> the example here) is a supertype; using "super" as the keyword seems
>> entirely natural.
>
> Before generics, super meant exactly one thing: "the method with this
> signature in the parent class of the class in which the current method
> is defined". That's completely unrelated to it use in generics.

In the first statement of a constructor, "super" introduces the
superclass constructor parameter list. It has never had only one meaning.

In general, Java has gone with a strategy of a short list of reserved
words, recycling them to deal with several related concepts whenever
possible in preference to adding new ones. The most extreme case of this
is "static".

Patricia
From: Tom Anderson on
On Wed, 7 Oct 2009, Patricia Shanahan wrote:

> Tom Anderson wrote:
>> On Wed, 7 Oct 2009, Lew wrote:
>>
>>> Roedy Green wrote:
>>>> & is used where you would expect to use comma. extends is used where
>>>> you would expect to use implements. super does not mean super.
>>>
>>> Why would "implements" be better than "extends"? The supertype doesn't
>>> have to be an interface. The idea of "extension" is much more natural for
>>> type analysis than "implementation".
>>
>> The supertype also doesn't have to be a class. This:
>>
>> List<? extends Runnable>
>>
>> Is unnatural.
>
> The "?" can represent either a class that implements Runnable or an
> interface that extends it. There are a total of three cases, class
> extends class, interface extends interface, and class implements
> interface. "extends" is appropriate for two of the cases, and the same
> keyword has to handle class implements interface and interface extends
> interface, so I think "extends" is the less bad choice.

Absolutely. It's still counterintuitive.

Anyway, why only have one keyword there? Why not allow either "extends" or
"implements" there, with the same meaning?

> Perhaps it was a mistake to use a special keyword for introducing an
> interface in a class declaration. If the superclass and all interfaces
> had been introduced by "extends" the problem would not exist.

Hey, we could just have used a colon.

>>> And how does "super" not mean super? The type that is "super" ('?' in the
>>> example here) is a supertype; using "super" as the keyword seems entirely
>>> natural.
>>
>> Before generics, super meant exactly one thing: "the method with this
>> signature in the parent class of the class in which the current method is
>> defined". That's completely unrelated to it use in generics.
>
> In the first statement of a constructor, "super" introduces the
> superclass constructor parameter list. It has never had only one meaning.

That's a call to the constructor with the given signature in the parent
class of the class in which the current method is defined. It has exactly
the same meaning as when used to make a super method call.

> In general, Java has gone with a strategy of a short list of reserved
> words, recycling them to deal with several related concepts whenever
> possible in preference to adding new ones. The most extreme case of this
> is "static".

Is it? Doesn't that just mean a feature lives in the class rather than the
instance? I'd nominate "final" for most overloaded, i think.

tom

--
This is the best kind of weird. It can make a corpse laugh back to
death. -- feedmepaper