What is more flexible ?
Hi,
Reading the generics faq, I have encountered this text:
"In general, if you have an API that only uses a type parameter T as an argument, its
uses should take advantage of lower bounded wildcards (? super T). Conversely, if
the API only returns T, you抣l give your clients more flexibility by using upper bounded
wildcards (? extends T)."
Could anybody please explain me how would somebody benefit
by using this convention ? Any examples ?
Thanks,
Adrian
# 1
I think the FAQ has a good example:[url= http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#What%20is%20a%20bounded%20wildcard?]What is a bounded wildcard?[/url][]
# 2
Hi,
The examples provided in this faq are quite obvious.
And the quote I had enclosed earlier is more general.
Perhaps I'm missing something here, but I still don't get
why would I benefit more using lower bounds on
arguments (apart from being able to invoke its methods,
whose signatures contain type parameter) and upper
bounds on return types (on return types ? What would I
get using it ?)
So it could look like this:
public static <T> List<? extends T> doSomething(List<? super T> l) {
return new ArrayList<T>(); // what else could I put in here ? I can't
//put just anything since I don't know what the T
//is going to be, so no subtypes available ...
//as for formal method's parameter l - there isn't
//any other benefit then being able to invoke eg:
// l.add() .... or is there something else ?
}
And the second thing is about copy method from Collections:
public static <T> void copy(List<? super T> dst, List<? extends T> src) {}
Why can't it be:
public static <T> void copy(List<? super T> dst, List<T> src) {}
I can't see any difference and the second one seems be easier to read
for me ...
Have you got any other examples ?
Cheers,
Adrian
# 3
but can you see any diference between this two?
public static <T> void copy( List<T> dest, List<T> src)
public static <T> void copy(List<? super T> dest, List<? extends T> src)
using the example from FAQ, it should be clear
List<Object> output = new ArrayList< Object >();
List<Long>input = new ArrayList< Long >();
Collections.copy(output,input); // illegal argument types for the first declaration above
# 4
maybe the example of the FAQ wasn't that clear, let's try something dif.
we have a class (list) like
class MyList<T> {
private List<T> list = new ArrayList<T>();
public void add(T value) {
list.add(value);
}
}
and used here MyList<Number> list = new MyList<Number>();
list.add(new Integer(1));
list.add(new Long(2);
this works fine, (kind of an upper bound here)
now lets add a method to add a List to our MyListclass MyList<T> {
private List<T> list = new ArrayList<T>();
public void add(T value) {
list.add(value);
}
public void addAll(List<T> values) {
list.addAll(values);
}
}
and try something like List<Integer> ints = new ArrayList<Integer>();
ints.add(new Integer(3));
ints.add(new Integer(4));
MyList<Number> list = new MyList<Number>();
list.addAll(ints); // error
we get an error since we are not calling addAll with a List<Number>, but it should be possible to add Integer to a Number list....
if we had defined the addAll method in that waypublic void addAll(List<? extends T> values) {
list.addAll(values);
}
we could add all elements of a List<Integer> (or List<Long> or List<Number> or ...) to our MyList<Number>, so this is more flexible than the previous (only allowing List of Number).
[]
# 5
Hi Simu,
That's right - an excellent example :)
Moreover - I do understand what you write here
and why it's useful here. But according to what was
written in the sun's faq (let me quote it again):
"In general, if you have an API that only uses a type parameter T as an argument, its
uses should take advantage of lower bounded wildcards (? super T). Conversely, if
the API only returns T, you抣l give your clients more flexibility by using upper bounded
wildcards (? extends T)."
An example you could fit into this convention could be (let's quote again):
public static <T> List<? extends T> doSomething(List<? super T> l) {
return new ArrayList<T>(); // what else could I put in here ? I can't
//put just anything since I don't know what the T
//is going to be, so no subtypes available ...
//as for formal method's parameter l - there isn't
//any other benefit then being able to invoke eg:
// l.add() .... or is there something else ?
}
So we accept a parameterized formal method's parameter whose
type parameter is bounded wildcard. I understand that it is useful
as we are able to call e.g.: l.add() But sometimes it is not that case
and we want to accept List<? extends T>. So why does author assume that
List<? super T> is in general better ? (Why is he assuming that in general
we want to be able to call parameter's methods which have type parameter
in its signature more often ?) And secondly, as I wrote as comment, what is
the benefit of RETURNING List<? extends T> ?
And have a look at what I wrote about copy method again:
Original from Collections:
public static <T> void copy(List<? super T> dst, List<? extends T> src) {}
My propose:
public static <T> void copy(List<? super T> dst, List<T> src) {}
They BOTH work.
Thanks for your patient :)
Cheers,
Adrian
# 6
first of all, note, I'm not an Generics expert, I'm just learning...
> Thanks for your patient :)
no problem, as I wrote I'm also learning a lot
====================
> public static <T> void copy(List<? super T> dst, List<? extends T> src) {}
> They BOTH work.
Yes, I also see they both work. Maybe this is not a perfect example, at least if T is not used somewhere else (other method/constructor). If we have something like
List<Object> dst;
List<Integer> src;
copy(dst, src);
T could "be" Object, Number or Integer
====================
> And secondly, as I wrote as comment, what is
> the benefit of RETURNING List<? extends T> ?
I think the tutorial does not mean the return value of a method, but an argument in which you are returning (inserting) T, like in:class MyList<T> {
private List<T> list = new ArrayList<T>();
// ...
public void copyTo(List<? super T> dst) {
dst.addAll(list);
}
}
====================
> and we want to accept List<? extends T>. So why does author assume that
> List<? super T> is in general better ? (Why is he assuming that in general
> we want to be able to call parameter's methods which have type parameter
> in its signature more often ?)
the author probably meant that using List<? super T> is better than just List<T>.
As I see it, you don't really have a choice between List<? super T> and List<? extends T>. If you insert some T into the List, it can not be List<? extends T>; if you are reading T from the List, it can not be List<? super T>; if you do both, it must be List<T>.
====================
[]
# 7
> no problem, as I wrote I'm also learning a lot
then there are two of us ;)
> > public static <T> void copy(List<? super T> dst, List<? extends T> src) {}
> > They BOTH work.
>
> Yes, I also see they both work. Maybe this is not a
> perfect example, at least if T is not used somewhere
> else (other method/constructor).
What do you mean by saying "at least if T is not used somewhere
else (other method/constructor)" ? Could you expand on that ?
>If we have something like
> List<Object> dst;
> List<Integer> src;
> copy(dst, src)
> T could "be" Object, Number or Integer
Yeah, in both cases whether it is
public static <T> void copy(List<? super T> dst, List<? extends T> src) {}
or
public static <T> void copy(List<? super T> dst, List<T> src) {}
> > And secondly, as I wrote as comment, what is
> > the benefit of RETURNING List<? extends T> ?
>
> I think the tutorial does not mean the return value
> of a method, but an argument in which you are
> returning (inserting) T
Could you expand on that ? What do you mean by
"argument in which you are returning T" ? I didn't get it ...
> the author probably meant that using List<? super T>
> is better than just List<T>.
> As I see it, you don't really have a choice between
> List<? super T> and List<? extends T>. If you insert
> some T into the List, it can not be List<? extends
> T>; if you are reading T from the List, it can not be
> List<? super T>; if you do both, it must be List<T>.
Yeah, I agree. So I suppose he was thinking about ability
of calling parameters method like l.add() and nothing else ...
Cheers,
Adrian
# 8
I think it was kind of late...
> What do you mean by saying "at least if T is not used somewhere
> else (other method/constructor)" ? Could you expand on that ?
something like when you do new ArrayList<String>(), this binds the Type for all other methods like add()
> Could you expand on that ? What do you mean by
> "argument in which you are returning T" ? I didn't
> get it ...
return would be something like public List<?> something(...
by "argument in which you are returning T" I meant something like the List in public void(List<?> dst,...
if inserting something in the list
[]
# 9
> > What do you mean by saying "at least if T is not
> used somewhere
> > else (other method/constructor)" ? Could you expand
> on that ?
>
> something like when you do new ArrayList<String>(),
> this binds the Type for all other methods like add()
Hmmm, so you say:
class MyClass<T> {
public void copy(List<? super T> dst, List<T> src) { ... }
}
Is that what you meant ? Because if it is, then no wonder
that I didn't understand it, because in the previous example
this method is static, so no connection with any other type
parameter. Unless this method is called from another
parameterized method - in that case I get it :) Am I right here ?
> > Could you expand on that ? What do you mean by
> > "argument in which you are returning T" ? I didn't
> > get it ...
>
> by "argument in which you are returning T" I meant
> something like the List in public void(List<?>
> dst,...if inserting something in the list
I'm sorry - it's maybe because of my English, but for me
return and insert are totally different words and especially
when talking about programming. I may be wrong, but I still
don't get it :/
All the best,
Adrian
# 10
> Is that what you meant ? Because if it is, then no wonder
> that I didn't understand it, because in the previous example
> this method is static, so no connection with any other type
> parameter. Unless this method is called from another
> parameterized method - in that case I get it :) Am I
> right here ?
yes, I have not given much weight on he static part..
> I'm sorry - it's maybe because of my English, but for me
> return and insert are totally different words and especially
> when talking about programming. I may be wrong, but I still
> don't get it :/
well, my english sure is not good (nor first neither second language) so probaly I've interpreted more than I should in the "return" word....
[]]