Another generics question: List<Class<?>> ls = ?

M

Mark Space

I got to thinking about the last generics question, and I don't
understand why the following doesn't work.

Given a list that holds some type of Class:

List<Class<String>> ls = new ArrayList<Class<String>>();

Why can't I assign this to a List that holds any type of Class?


List<Class<?>> al1 = ls; // oops
List<Class<?>> al2 = (List<Class<?>>) ls; // oops

Looking at the raw types, it seems this should work. al1 holds any type
of Class, and ls has a type of class. Yet there appears to be no way to
assign them. I don't know if this is a good idea, I merely want to
understand generics a little better.
 
L

Lew

Mark said:
I got to thinking about the last generics question, and I don't
understand why the following doesn't work.

Given a list that holds some type of Class:

List<Class<String>> ls = new ArrayList<Class<String>>();

Why can't I assign this to a List that holds any type of Class?


List<Class<?>> al1 = ls; // oops
List<Class<?>> al2 = (List<Class<?>>) ls; // oops

Looking at the raw types, it seems this should work. al1 holds any type
of Class, and ls has a type of class. Yet there appears to be no way to
assign them. I don't know if this is a good idea, I merely want to
understand generics a little better.

For the same reason you can't do

List <Number> numbers = new ArrayList <Number> ();
List <Integer> integers = new ArrayList <Integer> ();
List <Number> noops = integers; // forbidden
List <Integer> ieeks = numbers; // forbidden

<http://java.sun.com/docs/books/tutorial/java/generics/subtyping.html>

Given 'Sub' extends 'Parent', it is not true that 'Foo<Sub>' extends
'Foo<Parent>'. If it did, it would allow illegal actions.

noops.add( 0, Long.valueOf( 1L ));
Integer ix = integers.get( 0 ); // how did a Long get in here?

numbers.add( 0, Long.valueOf( 1L ));
ix = ieeks.get( 0 ); // how did a Long get in here?

List<Class<String>> ls = new ArrayList<Class<String>>();
List<Class<?>> al1 = ls; // oops
List<Class<?>> al2 = (List<Class<?>>) ls; // oops

al1.add( 0, Long.class );
String name = ls.get( 0 ).newInstance();
// how did a Long get in here?
al2.add( 0, Long.class );
name = ls.get( 0 ).newInstance();
// how did a Long get in here?
 
M

Mark Space

Lew said:
For the same reason you can't do
...snip...
Given 'Sub' extends 'Parent', it is not true that 'Foo<Sub>' extends
'Foo<Parent>'. If it did, it would allow illegal actions.


This almost makes sense to me. What I was expecting was it to work like
this:

List<?> lx = new ArrayList<String>();
lx.add( 0, "test" ); // error
String s = lx.get( 0 ); // warning, must cast

So assigning the types (the first line) is ok. That you can't put
anything into lx (second line) is fine, that's because you don't know
the actual type of lx. But you can at least get Object out. And you can
cast the Object to a String and hope you are correct.

So by analogy:

List<Class<String>> ls = new ArrayList<Class<String>>();

List<Class<?>> al1 = ls; // oops

al1.add( 0, String.class ); // works
Class<?> c = al1.get( 0 ); // works

I was expecting to work the same way. However, this time both the add
and get are ok, and it's the assignment of ls to al1 that fails. I
think I'm going to have to review my generics a bit, I've got something
mixed up.
 
O

Owen Jacobson

This almost makes sense to me. What I was expecting was it to work like this:

List<?> lx = new ArrayList<String>();
lx.add( 0, "test" ); // error
String s = lx.get( 0 ); // warning, must cast

That last line is actually an error, not a warning, without the cast.
So assigning the types (the first line) is ok. That you can't put
anything into lx (second line) is fine, that's because you don't know
the actual type of lx. But you can at least get Object out. And you
can cast the Object to a String and hope you are correct.

So by analogy:

List<Class<String>> ls = new ArrayList<Class<String>>();

List<Class<?>> al1 = ls; // oops

al1.add( 0, String.class ); // works
Class<?> c = al1.get( 0 ); // works

I was expecting to work the same way. However, this time both the add
and get are ok, and it's the assignment of ls to al1 that fails. I
think I'm going to have to review my generics a bit, I've got something
mixed up.

It does work the same way: the relationship between generic type
arguments is decided by what would be assignable to and from what. The
following is perfectly valid Java:

List<Class<?>> lclass = new ArrayList<Class<?>> ();
lclass.add (String.class);
lclass.add (List.class);

However, it has implications for your example. If List<Class<String>>
were assignable to List<Class<?>>, you'd then be able to add List.class
to it. What you actually want is a list of some type that is assignable
to Class<?> but is not assignable to from Class<List>:

List<Class<String>> lStringClass = new ArrayList<Class<String>> ();
// This is fine.
lStringClass.add (String.class);

List<? extends Class<?>> lClass = lStringClass;

// Error as above.
lClass.add (String.class);
lClass.add (Object.class);

// Error, but can cast, as above.
Class<String> c = lClass.get(0);

This is a pretty hairy edge case, but I can see it coming up if you had
a Plugin interface and a list of its implementing classes and wanted to
do something with any list of classes:

public static void main(String[] args) {
List<Class<? extends Plugin>> pluginClasses = new
ArrayList<Class<? extends Plugin>>();
pluginClasses.add(SoundPlugin.class);
pluginClasses.add(ThunderPlugin.class);

ensureLoadable (pluginClasses);
}

private static void ensureLoadable(
List<? extends Class<?>> classes) {
for (Class<?> c : classes) {
System.out.println(c);
}
}

HTH,

-o
 
A

Albert

Lew a écrit :
For the same reason you can't do

List <Number> numbers = new ArrayList <Number> ();
List <Integer> integers = new ArrayList <Integer> ();
List <Number> noops = integers; // forbidden
List <Integer> ieeks = numbers; // forbidden

<http://java.sun.com/docs/books/tutorial/java/generics/subtyping.html>

Given 'Sub' extends 'Parent', it is not true that 'Foo<Sub>' extends
'Foo<Parent>'. If it did, it would allow illegal actions.

Well, i don't if it's a special case, but the following code is valid
for eclipse:

import java.util.Collection;
import java.util.Set;

public class TestsGenerics {

abstract class A {
abstract Collection<Integer> foo();
}

class Sub extends A {
Set<Integer> foo() { // implements indicator here
return null;
}
}

}
 
L

Lew

Lew a écrit :
Well, i [sic] don't if it's a special case, but the following code is valid
for eclipse [sic]:

It's not a special case, just a different one.

And valid for Java is valid for Java, whether from Eclipse or Notepad.
import java.util.Collection;
import java.util.Set;

public class TestsGenerics {

abstract class A {
abstract Collection<Integer> foo();
}

class Sub extends A {
Set<Integer> foo() { // implements indicator here
return null;
}
}

}

Note that your case is 'Foo <Bar>', 'SubtypeOfFoo <Bar>', whereas Mark Space
and I were discussing 'Foo <Bar>', 'Foo <SubtypeOfBar>'.

The former shows a subtype relationship, the latter does not.
 
H

Hendrik Maryns

Op 21-04-09 14:48 heeft Lew als volgt van zich laten horen:
Lew a écrit :
Well, i [sic] don't if it's a special case, but the following code is
valid for eclipse [sic]:

It's not a special case, just a different one.

And valid for Java is valid for Java, whether from Eclipse or Notepad.

Yes, but I suppose the OP meant ‘compiles in Eclipse’, which is a
different thing than ‘compiles with javac’, sometimes. And both are
different from ‘complies to the spec’, which is probably what you mean
by ‘valid for Java’…

Cheers, H.
--
Hendrik Maryns
http://tcl.sfs.uni-tuebingen.de/~hendrik/
==================
www.lieverleven.be
http://catb.org/~esr/faqs/smart-questions.html
 
L

Lew

Hendrik said:
Yes, but I suppose the OP meant ‘compiles in Eclipse’, which is a
different thing than ‘compiles with javac’, sometimes. And both are
different from ‘complies to the spec’, which is probably what you mean
by ‘valid for Java’…

What differences have you observed between compilation by
- Eclipse and 'javac' (whose 'javac'?)
- the JLS and 'javac' (whose 'javac'?)
 
H

Hendrik Maryns

Op 24-04-09 14:34 heeft Lew als volgt van zich laten horen:
What differences have you observed between compilation by
- Eclipse and 'javac' (whose 'javac'?)
- the JLS and 'javac' (whose 'javac'?)

Alright, I am sorry for being imprecise. I meant Sun’s default javac
(any version, but I assume the altest) in both cases. There are several
bugs for this, most easily found in the Eclipse Bug Center. Here’s one:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=244804

It is an example for both cases: javac differs from JLS, but Eclipse
follows it. Another example on how difficult it is to interpret such
documents correctly.

H.
--
Hendrik Maryns
http://tcl.sfs.uni-tuebingen.de/~hendrik/
==================
www.lieverleven.be
http://catb.org/~esr/faqs/smart-questions.html
 
L

Lew

Hendrik said:
Alright, I am sorry for being imprecise. I meant Sun’s default javac
(any version, but I assume the altest) in both cases. There are several
bugs for this, most easily found in the Eclipse Bug Center. Here’s one:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=244804

It is an example for both cases: javac differs from JLS, but Eclipse
follows it. Another example on how difficult it is to interpret such
documents correctly.

The JLS is rather clear in that specific example, not "difficult ... to
interpret", and it was also clear that that was a bug, not a valid difference
in behavior. It's specious to refer to bugs as merely "differences in
behavior". Besides, that one's been fixed, according to the Sun bug report.

By definition a bug is a difference in behavior between a program and its
specification.
 
H

Hendrik Maryns

Op 26-04-09 17:28 heeft Lew als volgt van zich laten horen:
The JLS is rather clear in that specific example, not "difficult ... to
interpret", and it was also clear that that was a bug, not a valid
difference in behavior. It's specious to refer to bugs as merely
"differences in behavior". Besides, that one's been fixed, according to
the Sun bug report.

Lew, why are you being so stubborn again? As I said, this is just an
example, you can find many more of those, and not all of them have been
solved. And yes, sometimes it is the case that Sun has accepted that
javac is wrong, but haven’t fixed it anyway (mostly with generics).
By definition a bug is a difference in behavior between a program and
its specification.

And indeed javac differs from its specification, which is the JLS. And
it *is* a bug, though one that has been solved.

H.
--
Hendrik Maryns
http://tcl.sfs.uni-tuebingen.de/~hendrik/
==================
www.lieverleven.be
http://catb.org/~esr/faqs/smart-questions.html
 
L

Lew

Hendrik said:
Lew, why are you being so stubborn again? As I said, this is just an
example, you can find many more of those, and not all of them have been

Why are you being so personal?

I thought you were talking about behavioral differences that were not bugs. I
am trying to get clear about a point of information that you brought up that
seemed relevant to Java programming and was new information to me. When I
found out that you were talking about mistakes in the implementation, I was
disappointed. I had thought you were talking about something substantive.

Bugs and mistakes are a trivial example of differences and they get fixed over
time. I expect implementations to converge for that reason.

I accept sadly that various compilers have bugs in them. That is an
unfortunate and apparently unavoidable fact of software releases in general,
and hardly news. It is also not news that different implementations would
have different bugs. No two people are likely to make the same mistake. What
would be interesting would be intentional differences in implementation
between different compilers. I have not found "many more of those". You have
not mentioned any more of those. I gather there aren't any.

I apologize for misinterpreting your original comment on this matter.
 
H

Hendrik Maryns

Op 26-04-09 21:52 heeft Lew als volgt van zich laten horen:
Why are you being so personal?

Sometimes I can’t help it.
I thought you were talking about behavioral differences that were not
bugs. I am trying to get clear about a point of information that you
brought up that seemed relevant to Java programming and was new
information to me. When I found out that you were talking about
mistakes in the implementation, I was disappointed. I had thought you
were talking about something substantive.

Bugs and mistakes are a trivial example of differences and they get
fixed over time. I expect implementations to converge for that reason.

Let’s hope so together.
I accept sadly that various compilers have bugs in them. That is an
unfortunate and apparently unavoidable fact of software releases in
general, and hardly news. It is also not news that different
implementations would have different bugs. No two people are likely to
make the same mistake.

Right.

What would be interesting would be intentional
differences in implementation between different compilers. I have not
found "many more of those". You have not mentioned any more of those.
I gather there aren't any.

Interesting point. I do seem to remember that there were “bugs†of this
kind where both the Eclipse people and Sun claimed they had the right
implementation and wouldn’t change, but don’t take my word on it.
I apologize for misinterpreting your original comment on this matter.

No need.

H.
--
Hendrik Maryns
http://tcl.sfs.uni-tuebingen.de/~hendrik/
==================
www.lieverleven.be
http://catb.org/~esr/faqs/smart-questions.html
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top