The Artima Developer Community
Sponsored Link

Weblogs Forum
Generics: Unbounded wildcard puzzle

9 replies on 1 page. Most recent reply: Nov 20, 2005 2:26 AM by Gregor Zeitlinger

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 9 replies on 1 page
Bruce Eckel

Posts: 875
Nickname: beckel
Registered: Jun, 2003

Generics: Unbounded wildcard puzzle (View in Weblogs)
Posted: Nov 7, 2005 5:47 AM
Reply to this message Reply
Summary
I set out to explore how the compiler treats a plain List vs. a List<?>, and in the process found something mysterious.
Advertisement

A raw List can hold any type, whereas a List<?> holds an unknown, but specific type. That is, List is a heterogeneous container, while List<?> is a homogeneous container. However, I had observed that the compiler tends to accept either without warning, so I wrote the following example to explore this:


import java.util.*;

public class UnboundedWildcards1 {
  static List list1;
  static List<?> list2;
  static List<? extends Object> list3;
  static void assign1(List list) { 
    list1 = list;
    list2 = list;
    // list3 = list; // Warning: unchecked conversion
    // Found: List, Required: List<? extends Object>
  }
  static void assign2(List<?> list) {
    list1 = list;
    list2 = list;
    list3 = list;
  }
  static void assign3(List<? extends Object> list) {
    list1 = list;
    list2 = list;
    list3 = list;
  }
  public static void main(String[] args) {
    assign1(new ArrayList());
    assign2(new ArrayList());
    // assign3(new ArrayList()); // Warning:
    // Unchecked conversion. Found: ArrayList
    // Required: List<? extends Object>
    assign1(new ArrayList<String>());
    assign2(new ArrayList<String>());
    assign3(new ArrayList<String>());
    // Both forms are acceptable as List<?>:
    List<?> wildList = new ArrayList();
    wildList = new ArrayList<String>();
    assign1(wildList);
    assign2(wildList);
    assign3(wildList);
  }
}

So even though List and List<?> are technically different types, the compiler treats them interchangeably.

What I was not expecting was that it treats List<?> differently than List<? extends Object>. Perhaps someone knows the explanation.


Brian Slesinsky

Posts: 43
Nickname: skybrian
Registered: Sep, 2003

Re: Generics: Unbounded wildcard puzzle Posted: Nov 7, 2005 12:35 PM
Reply to this message Reply
The Generics FAQ (at http://www.langer.camelot.de/GenericsFAQ/JavaGenericsFAQ.html) explains it like this (under "Type System"):

"There is one special rule for unbounded wildcard instantiations: the conversion from a raw type to the unbounded wildcard instantiation is not an "unchecked" conversion, that is, the conversion from Collection to Collection<?> does not lead to an "unchecked" warning. This is different for concrete and bounded instantiations, where the conversion from the raw type to the concrete and bounded wildcard instantiation leads to an "unchecked" warning."

Another way to put it is that Collection<?> is the supertype of any Collection, whether raw or parameterized, while Collection<? extends Object> is the supertype only of parameterized Collections.

That doesn't explain why Sun decided to do it that way, though.

Krzysztof Sobolewski

Posts: 7
Nickname: jezuch
Registered: Dec, 2003

Re: Generics: Unbounded wildcard puzzle Posted: Nov 7, 2005 12:56 PM
Reply to this message Reply
It seems to confirm what I thought these wildcards mean. I believe that List and List<?> are *the same*, that is List<?> was introduced to mean the same as ungenerified List. That's because List is a generic type and it *has* to be generified somehow, but you you don't want to lose a type that accepts anything, all objects regardless of type. And it makes sense to me that List<? extends Object>, not List<?>, holds objects of "an unknown, but specific type".
Sorry if it's a little messy explanation, I'm iprovising here a bit ;)

Bruce Eckel

Posts: 875
Nickname: beckel
Registered: Jun, 2003

Re: Generics: Unbounded wildcard puzzle Posted: Nov 7, 2005 2:08 PM
Reply to this message Reply
> type. And it makes sense to me that List<? extends Object>, > not List<?>, holds objects of "an unknown, but
> specific type".

The problem with that is that List<?> does mean that it holds objects of an unknown, but specific type.

Bruce Eckel

Posts: 875
Nickname: beckel
Registered: Jun, 2003

Re: Generics: Unbounded wildcard puzzle Posted: Nov 7, 2005 2:14 PM
Reply to this message Reply
> "There is one special rule for unbounded wildcard
> instantiations: the conversion from a raw type to the
> unbounded wildcard instantiation is not an "unchecked"
> conversion, that is, the conversion from Collection to
> Collection<?> does not lead to an "unchecked" warning.
> This is different for concrete and bounded
> d instantiations, where the conversion from the raw type
> to the concrete and bounded wildcard instantiation leads
> to an "unchecked" warning."
>
> Another way to put it is that Collection<?> is the
> supertype of any Collection, whether raw or parameterized,
> while Collection<? extends Object> is the supertype only
> of parameterized Collections.
>
> That doesn't explain why Sun decided to do it that way,
> though.

Yes. This is slightly helpful, but basically it's only describing the way things (apparently) work, without any intuitive sense of why.

My perception is that the compiler is saying that:
List<?> unbounded = new ArrayList();
while not exactly correct, is tolerable, so it won't bother issuing a warning. They are actually two different things, but it's not worth making a fuss about.

However, I suspect there may be a motivation behind that, which might be the ability to say:

void f(List<?> anyList) { /* ... */ }

means "I'll accept any type, even though I actually know what generics are."

But, in addition, List<?> is also used for capture conversion.

It may also be that there are several meanings intended for <?> and thus it comes across as being imprecise.

Brian Slesinsky

Posts: 43
Nickname: skybrian
Registered: Sep, 2003

Re: Generics: Unbounded wildcard puzzle Posted: Nov 8, 2005 3:32 PM
Reply to this message Reply
Hmm...

List<?> means we don't know what this list allows. The only thing we can safely write to the list is a null, but we can read Objects from it.

List<? extends Object> means essentially the same.

List<? extends Foo> means we can write nulls and read Foos from the list.

List means we can write anything to the list and read Objects from the list.

I can see how casting List to List<?> is safe. We're "forgetting" a capability that the type-checker previously allowed.

Casting List to List<? extends Object> ought to be safe, but the type-checker rejects it. The only reason I can think of is that the type-checker doesn't know that "extends Object" is a trivial upper bound that's equivalent to no upper bound at all. It treats it as a non-trivial upper bound.

Bruce Eckel

Posts: 875
Nickname: beckel
Registered: Jun, 2003

Re: Generics: Unbounded wildcard puzzle Posted: Nov 8, 2005 3:48 PM
Reply to this message Reply
> Casting List to List<? extends Object> ought to be safe,
> but the type-checker rejects it. The only reason I can
> think of is that the type-checker doesn't know that
> "extends Object" is a trivial upper bound that's
> equivalent to no upper bound at all. It treats it as a
> non-trivial upper bound.

Yes, I would normally have come to that conclusion but I've learned not to trust the easy path when it comes to generics. It might actually be a compiler bug, but it could also have some meaning as yet unsussed.

Bruce Eckel

Posts: 875
Nickname: beckel
Registered: Jun, 2003

Re: Generics: Unbounded wildcard puzzle Posted: Nov 9, 2005 6:16 AM
Reply to this message Reply
Here's something interesting: From page 257 of "The Java Programming Language, 4e" by Arnold, Gosling and Holmes:

"But remember that List<?> is not another way of saying List<Object>, it is a way of saying List<? extends Object>."

This is why I try to put examples in for all of my assertions -- I've had too many cases where I've thought one thing and discovered that the behavior is different.

But this doesn't solve the mystery -- it's still possible that List<? extends Object> has some subtly different meaning than List<?>.

Vladimir Nesov

Posts: 27
Nickname: robotact
Registered: Aug, 2005

Re: Generics: Unbounded wildcard puzzle Posted: Nov 11, 2005 1:50 PM
Reply to this message Reply
It seems that just saying List is now deprecated, and so there is only one compatibility point left, that is List<?>. List<? extends Object> as any other generics-involving type actually checks in conversion if parameter use generics as well.

Gregor Zeitlinger

Posts: 108
Nickname: gregor
Registered: Aug, 2005

Re: Generics: Unbounded wildcard puzzle Posted: Nov 20, 2005 2:26 AM
Reply to this message Reply
Maybe Sun has planned the following phases for migrating pre-generic code to generic code:

1) pre-generic: raw types everywhere

2) migrating: use
2.1) List<? extends Foo> and List<? extends Object> where you know that these are the correct bounds and
2.2) List<?> where you don't (I wonder if it were better to leave List in those cases of doubt)

In that phase, 2.2 may still be called from raw types (as in the original example) but 2.1 may not.
This is a way of saying: I have generified the method signature. Now go ahead and update the method call.

3) generic: no unchecked warnings left

Flat View: This topic has 9 replies on 1 page
Topic: Tip: Using AspectJ with WSAD 5.1 Previous Topic   Next Topic Topic: Indexable Stacks and Programming with Contracts

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use