• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Tim Cooke
  • Campbell Ritchie
  • paul wheaton
  • Ron McLeod
  • Devaka Cooray
Sheriffs:
  • Jeanne Boyarsky
  • Liutauras Vilda
  • Paul Clapham
Saloon Keepers:
  • Tim Holloway
  • Carey Brown
  • Piet Souris
Bartenders:

generic confusion

 
Ranch Hand
Posts: 64
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I think these two are identical, if they are not please explain the difference. Thanks in advance.



Anu Bhagat
 
Ranch Hand
Posts: 1032
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Anu,

List<? extends Object> list; is correct. But the other one won't even compile. When you declare generic references you can't use the <T extends Something> syntax, that only works when you are declaring a generic type, like this:

class MyClass<T extends Object> {
T a;
}

Also, you don't use wildcards in generic type declarations, just in generic reference declarations.

You basically use wildcards to denote a type which is not known at compile time. Normally what you do is use a bounded wildcard, something like <? super A> (lower bound for the type is A) or <? extends B> (upper bound for the type is B.) But you can also use a completely unbounded wildcard, as in <?>. Notice that List<?> is exactly the same as List<? extends Object>.
 
Anu Bhagat
Ranch Hand
Posts: 64
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks for clarification.

Regards,

Anu
 
Ranch Hand
Posts: 66
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Notice that List<?> is exactly the same as List<? extends Object>.


Ruben,

While I’m generally agree with your explanation for this question, but I’m afraid that your last line which I quote above is Incorrect.

The upper bound wildcard parameterized type (<? extends object>) are equivalent but they are NOT “exactly the same”

Here is a case that you can see the difference:


Output:

C:\java\src>javac -Xlint GenericsTest.java
GenericsTest.java:19: warning: [unchecked] unchecked conversion
found : java.util.List
required: java.util.List<? extends java.lang.Object>
extObjList = rawList; // !****Unchecked Conversion warning****!
^
1 warning



So, Considering these cases we can say they are essentially equivalent, but they are NOT exactly the same.

 
Ruben Soto
Ranch Hand
Posts: 1032
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Morteza Manavi-Parast wrote:

Notice that List<?> is exactly the same as List<? extends Object>.


Ruben,

While I’m generally agree with your explanation for this question, but I’m afraid that your last line which I quote above is Incorrect.

The upper bound wildcard parameterized type (<? extends object>) are equivalent but they are NOT “exactly the same”

Here is a case that you can see the difference:


Output:

C:\java\src>javac -Xlint GenericsTest.java
GenericsTest.java:19: warning: [unchecked] unchecked conversion
found : java.util.List
required: java.util.List<? extends java.lang.Object>
extObjList = rawList; // !****Unchecked Conversion warning****!
^
1 warning



So, Considering these cases we can say they are essentially equivalent, but they are NOT exactly the same.


Morteza,

I'm sure you put a lot of effort into finding a corner case, but I'm afraid that this is little more than an anecdote, and I still think that List<?> is exactly the same as List<? extends Object> (except that compiler warning, which you still are not explaining in your post.) Can you explain the compiler warning in this case? How is type safety compromised in one case and not in the other? I like to understand why things work the way they do, and to me a compiler warning is meaningless unless I understand why it's taking place.

To me, if you can assign reference a to reference b and also assign reference b to reference a (and both of this without using the casting operator,) that means that their types are exactly the same. (And yes, there might be some corner cases for this too, but I don't feel like finding them, although if you want to find them, I would be interested in reading your post.) The compiler warning I think is a product of the compiler inner workings, and unless you can explain why it's taking place, it's utterly meaningless. As a side note, some aspects of a Java compiler implementation are not specified by the Java specification, and that's why sometimes you can get different outputs with different compliant compilers.

I advise not to extract conclusions based solely on compiler output, because the compiler has its quirks. For example, based on compiler output you might also extract the conclusion that static methods can be overridden (which they obviously aren't.)

For further reference, you can check page 621 of K&B for Java 6.

That being said, I would be extremely interested if you can show that Llist<?> and List<? extends Object> are not exactly the same.
 
Morteza Manavi-Parast
Ranch Hand
Posts: 66
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Wow! Slow down, I might have a point in there!
Actually I wanted to explain the reason of the compiler behaviour on my post, but I thought it might not be relevant to the point. But if you are interested, Sure:
Assigning a value of the Raw type List to a reference of type List<? extends Object> cause an “unchecked conversion warning” which conforms to the general rule when mixing legacy and generic code:
Assigning the value of a raw type to a reference of a concrete parameterized type (like List<Integer>) or a bounded wildcard parameterized type (like List<? extends Number>) will result in an Unchecked Conversion warning. However this is not the case for the unbounded parameterized type List<?>. Meaning that there is not such a restriction for Unbounded wildcard parameterized type.

Basically compiler gives you the same warning as when you do this:

So like I said before, it’s an Unchecked Conversion warning and it’s not one of those Unspecified_ Unknown_LowLevel_Innerworkings_WeShouldn'tCareAbout warnings!
Therefore, I did not make a rule out of a compiler output, the compiler is actually following one of the Generics rules (which I mentioned above) defined for it.

However, when considering the Get and Put principle, yes they both acting the same:

1. You cannot put data in any of those.
2. You only can get an Object out of them both.

And that’s why I’m saying they are equivalent.


“To me, if you can assign reference a to reference b and also assign reference b to reference a (and both of this without using the casting operator,) that means that their types are exactly the same.”


True but when it comes to Generics, it’s totally wrong! The classic example would be the two types I mentioned above (rawList and intList), you can assign these two guys to each other without a cast operator but they are “exactly different”!

Well, If you still are interested to know more, and also you are familiar with the concept of “Reification” and “Reifiable Types” I can tell you another difference:
List<?> is Reifiable and List<? extends Object> is NOT reifiable, even though it’s equivalent to List<?>!! Which means compiler even do not treat them in a same way at the Type Erasure process!

Ok, I think it’s enough for now. I rest my case!
 
Ruben Soto
Ranch Hand
Posts: 1032
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I am afraid I still am not convinced (and hence you haven't rested your case, at least with me.) The wildcard in List<? extends Object> is not any more bounded than the wildcard in List<?>. The upper bound for both wildcards is Object, and the lower bound is nulltype. When you say that List<? extends Object> is not reifiable, but List<?> is, you are saying that there is type information in List<? extends Object> which is available at compile time, but which is lost at runtime, whereas no type information is lost for List<?> at runtime. That's wrong, because there is no more type information at compile time for List<? extends Object> than there is for LIst<?>, since the restrictions for the wildcard in both cases are exactly the same.

Syntactically <? extends Object> is a bounded wildcard (and by syntactically, I mean in the surface,) but semantically it is exactly as unbounded as <?>.

Here's what I think the compiler is doing in this case: It is looking at <? extends X> without worrying to evaluate whether X is Object, and it is issuing that warning. But the main point (and why I think this warning is just an artifact) is that there is no possible loss of type information when List<? extends Object>. In that sense it is exactly the same as with List<?>.

And, as I said, you must not trust any Java compiler 100%, especially concerning the wording in warnings and errors. Always try to understand why the compiler tells you what it is telling you. In this case: Why is it giving that warning? What possible type safety loss could the code be incurring in?

I'm not saying that your ultimate statement about both types not being exactly equivalent is wrong. I'm just saying that given the proof which you are showing at the moment, you current argument is wrong. Your argument is that if one of the types gives a compiler warning and the other doesn't, then the types are not exactly the same. But that difference is just superficial, because the only thing it proves is compiler output without any reasoning to what (if anything is behind it.) For that, I need you to explain what the warning which the compiler is issuing in this case is trying to prevent. I really want to see you win this discussion though, because that will mean that I will learn something new. But you are going to have to investigate further and also learn something which you do not know at the moment. I'll leave the investigating (and potential debunking) to you.
 
Morteza Manavi-Parast
Ranch Hand
Posts: 66
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Don’t worry, there is no need for further investigations! I just don't want to dive deeply into technical details, but it seems to be inevitable. Just before I start, please note that Like I said, the compiler output is a result of a rule, I was not trying to proof anything based on the compiler output ever.

For my proof of concept, first I will explain why <?> is reifiable and <? extends Object> is not, then with using the proof of this will explain the compiler warning.


why <?> is reifiable and <? extends Object> is not?

Ok, we know that for example, types such as List<String> List<? extends Object> are available to and used by the compiler in their exact form, including the type argument information. After type erasure, the virtual machine has only the raw types List available, which means that part of the type information is lost.

Among the instantiations of a generic type only the unbounded wildcard instantiations, such as Map<?,?> or List<?> , are unaffected by type erasure.
Of course they do lose their type arguments, but since all type arguments are unbounded wildcards, no information is lost. Means that List<?> will be List at runtime too, but again since it does not have any type information, no information is lost by erasure and hence it’s reifiable.

Implications:

And it’s a big difference cause it’s result in many implications that these “Absolutely identical” types being treated by the compiler in a absolutely different ways! I just mentioned two of those here and leave learning about the rest of other implications to you. Essentially because you don’t like (or trust) compiler warnings, I’ll mention some “Compiler Errors” here, to see how exactly they are different, hopefully you’ll like them!


* Implication on instance of operator

Object obj ;
boolean isExtList = obj instanceof List<? extends Object>; // Compiler Error: "illegal generic type for instanceof"
boolean isExtList = obj instanceof List<?>; // Compiles just fine!

* Implication on Arrays

List<? extends Object>[] list3 = {Arrays.asList("1", "2")}; // Compile Error: "generic array creation"
List<?>[] list4 = {Arrays.asList("1", "2")}; // Compiles just Fine!


Ok, let’s back to my second proof of concept part:


Why do we get an "unchecked" warning although there is no type information missing?

Because the compiler performs all type checks based on the type erasure when you use a raw type.

For an example, here an unchecked warning is issued in situations where there is enough type information available:

class SomeType<T> {

public List<String> getList() { ... }
}

SomeType raw = new SomeType ();
List<String> listString = raw.getList(); // unchecked warning
________________________________________
warning: [unchecked] unchecked conversion
found : List
required: List<String>
List<String> listString = raw.getList();
^
In this example, there is no type information missing. The getList method is declared to return a List<String> and this is so even in the raw type because the method does not depend on the enclosing class's type parameter. Yet the compiler complains!!?

The reason is that the compiler computes the type erasure of a generic type when it finds an occurrence of the raw type in the source code. Type erasure does not only elide all occurances of the type parameter T , but also elides the type argument of the getList method's return type. After type erasure, the getList method returns just a List and no longer a List<String> . All subsequent type checks are performed based on the type erasure; hence the "unchecked" warning.

Same case in my previous post, in the “extObjList = rawList” compiler sees that the extObjList is not reifiable so it lose information after erasure...

If you are not convinced yet, just go back and read my explanation again, but this time, before start reading, just forget that “every object extends Object class” for a second and then start reading, I bet it will make a lot more sense for you then!




 
Ruben Soto
Ranch Hand
Posts: 1032
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Here's the problem with your reasoning: You are saying that List<?> and List<? extends Object> are not the same because the compiler doesn't treat them the same. Then I asked you why the compiler is not treating them the same, and you have no answer for that. My theory is that the compiler is being lazy.

And it's not that I don't like compiler warnings or error messages, it's that I tend to look at thinks with a critical mind and with a little bit of skepticism. I will prove right now to you that, in this case, the compiler warning is probably bogus:



This is quite simple. If the compiler is warning you when you do l3 = l1, it should be also warning you at some point in the next 2 statements, because the net effect is the same. On the other hand (and this is my theory) the compiler shouldn't be warning you at all when you assign l1 to l3. The compiler can't be right in both cases, because they contradict each other. In one case you get a warning, in the other you don't (yet the net effect is that l3 now points to what l1 pointed to.)

There are more instances where compiler output is not optimal. As I said before, if you were to go simply by the wording in compiler errors, you could derive the conclusion that static methods are overridden. Yet I don't think even you will argue that.

You need to explain to me what the compiler warning means, and why List<?> is available at runtime but List<? extends Object> is not. As a matter of fact, I would be interested in seeing an example which shows me that List<?> is available at runtime. Until then I will remain skeptical about the compiler warning in this case.

One thing that I am interested in knowing also is: If the reason for type erasure is to make bytecode from generics-aware Java code compatible with generics-unaware Java code, how is List<?> available as a type at runtime? As far as I know, List<?> didn't exist as a type before generics were introduced to the language. Until questions such as this are answered, I maintain that List<?> and List<? extends Object> are absolutely the same (despite what the compiler warnings tell you.)
 
Morteza Manavi-Parast
Ranch Hand
Posts: 66
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Ok, it seems that you don’t even read my answer casue I see you keep repeating your statements over and over. I described why <?> is reifiable and <? extends Object> is not. I told you that
“Of course they all do lose their type arguments, but since all type arguments are unbounded wildcards, no information is lost. Means that List<?> will be List at runtime too” and you again asked me : “how is List<?> available as a type at runtime?”!!
So just this little sample shows that you don’t even read my post, or maybe just read through it when you were scrolling down to get into the “Post reply” button!

And I’m afraid I won’t continue this discussion casue it goes to nowhere. Your question is completely answered in my previous post and you can refer to it if you like.

If you are interested to know a little more about generics (Probably more than what K&B gives you) there is an invaluable document about generics at about 600 pages all about generics and under the hood of the compiler. For now and untill you don’t read that you can keep your skeptical attitude about compiler behaviour but after you read it (which I did) you will learn that the compiler do not gives you compile errors just because it's lazy:

http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.pdf


 
Ruben Soto
Ranch Hand
Posts: 1032
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Sorry if my post upset you because you get the feeling I'm not reading your posts properly. It is actually ironic, because I get the same feeling from your responses, since you haven't been able to satisfactorily address any of the issues that I am bringing up. I see the same effects that you see (the compiler behavior.) The problem lies in the fact that you seem to interpret that behavior in a a different way. I personally don't see how that warning is consistent with the theory, and that's why I'm skeptical about it. I would only like for you to be able to explain those questions, so that they can be understood.

These questions need to be addressed:
1. What type safety loss is the compiler warning preventing you from incurring in?
2. How is List<?> reifiable, but List<? extends Object> is not?
3. What is your definition of reifiable? According to the JLS, reifiable types are those which are available at runtime. I had already derived the conclusion that what this actually means is that reifiable types are those for which there is no type information loss in runtime vs compile time (post #7,) but you misinterpreted what I was trying to say. The problem is that by either definition of "reifiable" List<?> is no more reifiable than List<? extends Object>, except for what the compiler is telling you.
4. In the code that I provided above, why is there a compiler warning in one case but not the other, when the result of both pieces of code is the same?

I haven't read that Angelika Langer document because I have limited time resources, but since you seem to have read it, maybe you can answer those questions. Better to try and explain one question at a time to keep the discussion focused.

I hope you haven't stopped trying to explain these questions, because I'd like you to change my mind. Until then, I will maintain that List<?> is exactly the same as List<? extends Object>, except for some as of yet unexplained compiler behavior.
 
Ruben Soto
Ranch Hand
Posts: 1032
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
And, to clarify things (although I already talked about this before.) I think the reason List<?> is considered reifiable whereas List<? extends Object> is to make it easy for the compiler to be lazy when checking this. In other words, there is no essential reason why List<?> is any more reifiable than List<? extends Object>, going by any reasonable definition of the term.
 
Morteza Manavi-Parast
Ranch Hand
Posts: 66
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Ok, I agree to go through questions one by one, but before we start, can you describe the following errors with your logic?

Object obj ;
boolean isExtList = obj instanceof List<? extends Object>; // Compiler Error: "illegal generic type for instanceof"
boolean isExtList = obj instanceof List<?>; // Compiles fine!

List<? extends Object>[] list3 = {Arrays.asList("1", "2")}; // Compile Error: "generic array creation"
List<?>[] list4 = {Arrays.asList("1", "2")}; // Compiles Fine!
 
Ruben Soto
Ranch Hand
Posts: 1032
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Morteza Manavi-Parast wrote:Ok, I agree to go through questions one by one, but before we start, can you describe the following errors with your logic?

Object obj ;
boolean isExtList = obj instanceof List<? extends Object>; // Compiler Error: "illegal generic type for instanceof"
boolean isExtList = obj instanceof List<?>; // Compiles fine!

List<? extends Object>[] list3 = {Arrays.asList("1", "2")}; // Compile Error: "generic array creation"
List<?>[] list4 = {Arrays.asList("1", "2")}; // Compiles Fine!


I was hoping you would explain why you think those errors were caused, since you are the one who brought them up. My guess is that List<? extends Object> is treated as a type with a bounded wildcard (although in reality it shouldn't.)
 
Morteza Manavi-Parast
Ranch Hand
Posts: 66
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Ruben,

I know you expected another full technical explanations to your questions, but I asked that to better understand your perspective in this, I guess the problem is that you involve the fact that everything extends the Object and try to interpret the compiler behaviour based on that, but that's not how compiler approaches this matter. To the compiler <?> means an unspecified type just like the raw type and <? extends Object> is a type that extends Object. And that's not because compiler is lazy, since if you put a language Designer hat, you'll see that you would design the compiler this way to keep consistency with other upper bounded wildcard types. That’s why I told you to try to forget that everything extends object in this case.

I’m not going to answer those questions again, cause I already did and if I want to go through it again, I have to repeat my explanations again which obviously I don’t like. Please note that in fact none of those explanations was mine, I just represent the technical sources which I studied for this and I mentioned one of my sources to you. So it’s just the way it is. You can sit and study those sources and get a better understanding about how these things work.

Just one last point: my hunches about why the bible states that they are “absolutely identical” is that the writers was 100% sure that the exam will test on their similarity rather than their subtle differences, so they just say that and move on. So probably I should never bring this up in a SCJP forum!

I think this is already designed and approved so it’s not worth this much disputes that we already go through. That’s all I can say. You can also create a separate thread for this one and see what other fellows think about this or just consult the sources that I mentioned before.

Good Luck!
 
Ruben Soto
Ranch Hand
Posts: 1032
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yes, I can see that List<?> and List<? extends Object> are treated differently by the compiler. The question is what does the specification say, if anything, explicitly, about <? extends Object> being reifiable or non-reifiable. And that matter hinges specifically on whether <? extends Object> is actually a bounded or an unbounded wildcard. If you look at it from a syntactic point of view, <? extends Object> is a bounded wildcard. However, from a semantic point of view, it is an unbounded wildcard. The specification doesn't say whether <? extends Object> is considered bounded or unbounded, but the javac implementors decided to consider it a bounded wildcard. That makes the compiler's job easier (although this is debatable,) and promotes syntactic ortogonality (unfortunately, sacrificing semantic ortogonality.) My main point and question is: Could a compliant compiler do it the other way around? Because I just don't see any technical obstacle to do it that way, and unless I am missing something, the specification doesn't specifically state whether <? extends Object> is bounded or not.
 
reply
    Bookmark Topic Watch Topic
  • New Topic