You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@wicket.apache.org by Johannes Schneider <jo...@familieschneider.info> on 2008/04/22 11:22:19 UTC

Generics: Wildcards

Hi,

during the last days I have created several patches that introduce
wildcards to generified collections.
And very often I have to describe why this is necessary.


So I think it might be useful to discuss that topic once and for all.

Java developers tend to avoid the wildcards (e.g. List<? extends
Serializable>). I don't know exactly why, but most of the time people
don't understand why those are necessary - so I try to describe it.



List<? extends Serializable>: This declares *any* type of list that
contains objects that implement Serializable. That could be a List of
Strings or a List of Integers. We just don't know exactly. All we know
is that the elements implement Serializable.
Those Lists only offer read access. It is not possible to add any
elements.


Some example assignments:

//contains all kinds of Serializables
List<? extends Serializable> l = new ArrayList<Serializable>();

//contains *only* Strings
List<? extends Serializable> l = new ArrayList<String>();

//contains *only* Integers
List<? extends Serializable> l = new ArrayList<Integer>();

//contains *only* the given kind (that implments Serializable
List<? extends Serializable> l = new ArrayList<*anything that
implements Serializable*>();



List<Serializable>: This declares a list that contains Serializables -
but *all* kinds of Serializables. So it is possible to store Strings
*and* Integers (and all other objects that implement Serializable)
within that list.

It is *only* possible to assign a List<Serializable>:
List<Serializable> l = new ArrayList<Serializable>();


It is *not* possible to assign those:
List<Serializable> l = new ArrayList<String>(); !!!! DOES NOT WORK !!!


So what is the problem now: If an interface method forces me to return a
List<Serializable> it is *not* possible to return e.g. a List<String>.
Instead I have to do fancy things to work around and be able to return
that list.


But there is just one simple rule that fits nearly every case:
As long as you only *read* a collection or return an unmodifiable
collection, *always* use wildcards. Only if you need or offer write
access, it is necessary to specify a collection exactly.


This discussion is necessary, since it is an incompatible change to add
wildcards later. This will break your API!
There are several bad examples out there that did this error (GlazedList
anyone?). It is very hard to fix those issues afterward. So I strongly
advice to do those things right before releasing 1.4.



Regards,

Johannes Schneider



















Re: Generics: Wildcards

Posted by Johannes Schneider <jo...@familieschneider.info>.
On Tue, 2008-04-22 at 07:49 -0700, Igor Vaynberg wrote:
> i agree that there are some benefits to wildcards, and thanks for the
> info, i wasnt aware of a lot of the things you described. that said,
> you have to keep in mind that we are a framework, not a library. that
> means that there are plenty of places where the user never creates the
> list returned and so there is no need to widen the generics.

You are right. I don't know Wicket good enough to judge whether a user
will (ever) create a list or not in every single case.
In my opinion it is better to do the "right" thing - even if hasn't a
immediate benefit. Maybe sometimes in the future it will pay off. At
least it improves the code quality.

But of course it is your decision. I just wanted to point out, how to
use wildcards correctly.


Johannes

> 
> eg
> 
> -	protected List<IBehavior> getBehaviors(Class< ? extends IBehavior> type)
> +	protected List<? extends IBehavior> getBehaviors(Class< ? extends
> IBehavior> type)
> 
> there is no point to making that change. the user never creates the
> list, the framework does.
> 
> now in IDataProvider that made total sense since it is the user
> returning the Iterator.
> 
> -igor
> 
> 
> On Tue, Apr 22, 2008 at 2:22 AM, Johannes Schneider
> <jo...@familieschneider.info> wrote:
> > Hi,
> >
> >  during the last days I have created several patches that introduce
> >  wildcards to generified collections.
> >  And very often I have to describe why this is necessary.
> >
> >
> >  So I think it might be useful to discuss that topic once and for all.
> >
> >  Java developers tend to avoid the wildcards (e.g. List<? extends
> >  Serializable>). I don't know exactly why, but most of the time people
> >  don't understand why those are necessary - so I try to describe it.
> >
> >
> >
> >  List<? extends Serializable>: This declares *any* type of list that
> >  contains objects that implement Serializable. That could be a List of
> >  Strings or a List of Integers. We just don't know exactly. All we know
> >  is that the elements implement Serializable.
> >  Those Lists only offer read access. It is not possible to add any
> >  elements.
> >
> >
> >  Some example assignments:
> >  
> >  //contains all kinds of Serializables
> >  List<? extends Serializable> l = new ArrayList<Serializable>();
> >
> >  //contains *only* Strings
> >  List<? extends Serializable> l = new ArrayList<String>();
> >
> >  //contains *only* Integers
> >  List<? extends Serializable> l = new ArrayList<Integer>();
> >
> >  //contains *only* the given kind (that implments Serializable
> >  List<? extends Serializable> l = new ArrayList<*anything that
> >  implements Serializable*>();
> >
> >
> >
> >  List<Serializable>: This declares a list that contains Serializables -
> >  but *all* kinds of Serializables. So it is possible to store Strings
> >  *and* Integers (and all other objects that implement Serializable)
> >  within that list.
> >
> >  It is *only* possible to assign a List<Serializable>:
> >  List<Serializable> l = new ArrayList<Serializable>();
> >
> >
> >  It is *not* possible to assign those:
> >  List<Serializable> l = new ArrayList<String>(); !!!! DOES NOT WORK !!!
> >
> >
> >  So what is the problem now: If an interface method forces me to return a
> >  List<Serializable> it is *not* possible to return e.g. a List<String>.
> >  Instead I have to do fancy things to work around and be able to return
> >  that list.
> >
> >
> >  But there is just one simple rule that fits nearly every case:
> >  As long as you only *read* a collection or return an unmodifiable
> >  collection, *always* use wildcards. Only if you need or offer write
> >  access, it is necessary to specify a collection exactly.
> >
> >
> >  This discussion is necessary, since it is an incompatible change to add
> >  wildcards later. This will break your API!
> >  There are several bad examples out there that did this error (GlazedList
> >  anyone?). It is very hard to fix those issues afterward. So I strongly
> >  advice to do those things right before releasing 1.4.
> >
> >
> >
> >  Regards,
> >
> >  Johannes Schneider
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
-- 
Bitte beachten Sie, dass dem Gesetz zur Vorratsdatenspeicherung 
zufolge, seit dem 1. Januar 2008 jeglicher elektronische Kontakt 
(E-Mail, Telefongespräche, SMS, Internet-Telefonie, Mobilfunk, 
Fax) mit mir oder anderen Nutzern verdachtsunabhängig für den 
automatisierten, geheimen Zugriff für sechs Monate gespeichert 
wird - einschließlich der Kommunikation mit Berufsgeheimnisträgern 
wie Ärzten, Pfarrern, Journalisten und Anwälten.

Geheim(!) zugreifen dürfen unter anderem die Strafverfolgungs- 
und Polizeivollzugsbehörden, die Bundesanstalt für Finanzdienst-
leistungsaufsicht, Zollkriminal- und Zollfahndungsämter, die 
Zollverwaltung zur Schwarzarbeitsbekämpfung, Notrufabfragestellen, 
Verfassungsschutzbehörden, der Militärische Abschirmdienst, 
Bundesnachrichtendienst sowie 52 Staaten wie beispielsweise 
Aserbaidschan, Russland und die USA.

Mehr Infos zur Protokollierung Ihrer Kommunikationsdaten: 
www.vorratsdatenspeicherung.de.
---------------------

Johannes Schneider
Im Lindenwasen 15
72810 Gomaringen

Fon +49 7072 9229972
Fax +49 7072 509999
Mobil +49 178 1364488

johannes@familieschneider.info
http://www.johannes-schneider.info

Re: Generics: Wildcards

Posted by Igor Vaynberg <ig...@gmail.com>.
i agree that there are some benefits to wildcards, and thanks for the
info, i wasnt aware of a lot of the things you described. that said,
you have to keep in mind that we are a framework, not a library. that
means that there are plenty of places where the user never creates the
list returned and so there is no need to widen the generics.

eg

-	protected List<IBehavior> getBehaviors(Class< ? extends IBehavior> type)
+	protected List<? extends IBehavior> getBehaviors(Class< ? extends
IBehavior> type)

there is no point to making that change. the user never creates the
list, the framework does.

now in IDataProvider that made total sense since it is the user
returning the Iterator.

-igor


On Tue, Apr 22, 2008 at 2:22 AM, Johannes Schneider
<jo...@familieschneider.info> wrote:
> Hi,
>
>  during the last days I have created several patches that introduce
>  wildcards to generified collections.
>  And very often I have to describe why this is necessary.
>
>
>  So I think it might be useful to discuss that topic once and for all.
>
>  Java developers tend to avoid the wildcards (e.g. List<? extends
>  Serializable>). I don't know exactly why, but most of the time people
>  don't understand why those are necessary - so I try to describe it.
>
>
>
>  List<? extends Serializable>: This declares *any* type of list that
>  contains objects that implement Serializable. That could be a List of
>  Strings or a List of Integers. We just don't know exactly. All we know
>  is that the elements implement Serializable.
>  Those Lists only offer read access. It is not possible to add any
>  elements.
>
>
>  Some example assignments:
>  
>  //contains all kinds of Serializables
>  List<? extends Serializable> l = new ArrayList<Serializable>();
>
>  //contains *only* Strings
>  List<? extends Serializable> l = new ArrayList<String>();
>
>  //contains *only* Integers
>  List<? extends Serializable> l = new ArrayList<Integer>();
>
>  //contains *only* the given kind (that implments Serializable
>  List<? extends Serializable> l = new ArrayList<*anything that
>  implements Serializable*>();
>
>
>
>  List<Serializable>: This declares a list that contains Serializables -
>  but *all* kinds of Serializables. So it is possible to store Strings
>  *and* Integers (and all other objects that implement Serializable)
>  within that list.
>
>  It is *only* possible to assign a List<Serializable>:
>  List<Serializable> l = new ArrayList<Serializable>();
>
>
>  It is *not* possible to assign those:
>  List<Serializable> l = new ArrayList<String>(); !!!! DOES NOT WORK !!!
>
>
>  So what is the problem now: If an interface method forces me to return a
>  List<Serializable> it is *not* possible to return e.g. a List<String>.
>  Instead I have to do fancy things to work around and be able to return
>  that list.
>
>
>  But there is just one simple rule that fits nearly every case:
>  As long as you only *read* a collection or return an unmodifiable
>  collection, *always* use wildcards. Only if you need or offer write
>  access, it is necessary to specify a collection exactly.
>
>
>  This discussion is necessary, since it is an incompatible change to add
>  wildcards later. This will break your API!
>  There are several bad examples out there that did this error (GlazedList
>  anyone?). It is very hard to fix those issues afterward. So I strongly
>  advice to do those things right before releasing 1.4.
>
>
>
>  Regards,
>
>  Johannes Schneider
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>