Il Problema della Non-Covarianza nei Generics in Java e C#
Posted by Ricibald on April 11th, 2008
Java, C# e C++ non contemplano il concetto di covarianza:
Una classe C<T> si dice covariante rispetto a T se, date due classi A e B tali che B deriva da A, risulta anche che C<B> deriva da C<A>.
Significa quindi che questa istruzione solleva un’eccezione:
List<Persona> studenti; List<Object> objects = (List<Object>) studenti; // Errore
Questo deriva da un motivo di logica Object Oriented, non strutturale del linguaggio. Infatti il cast verso “objects” altera il comportamento di “studenti”, che accetta come elementi della lista solo oggetti che derivano da “Studente”. Se fosse stato ammesso, ciclare la collezione “studenti” avrebbe potuto restituire oggetti anche non di tipo “Studente” che non è ammesso. In altre parole, il problema è che la covarianza consente di definire sottoclassi che restringono la classe base.
Il concetto di covarianza si ripercuote sull’utilizzo dei metodi. Ad esempio: immaginiamo il metodo di una nostra implementazione della classe List:
class List<T> {
AddAll(List<T> l);
}
Immaginiamo di avere una classe Studente che deriva da Persona:
List<Studente> studenti = new List<Studente>(); List<Persona> persone = new List<Persona>(); studenti.AddAll(studenti); // Ok studenti.AddAll(persone); // Errore
Il codice funziona se introduciamo wildcard (Java) o naked constraint (C#):
// Java
class List<T> {
addAll(List<? extends T> l);
}
// C#
class List<T> {
AddAll<U>(List<U> l) where U : T;
}
Se invece vogliamo staccarci dalla genericità e trattare solo istanze di tipo “Object” osserviamo (come abbiamo già visto) che questo non compila:
List<Object> l = (List<Object>)persone; // Errore
Ma utilizzando wildcard (Java) o collezioni raw (C#) la classe compila:
List<?> l = persone; // Java IList l = persone; // C#
Da cui deriva che in C#, quando realizziamo una classe generica, è necessario fornire sempre un’implementazione non generica per supportare upcast non generici:
// C#
class List {
Add(object item);
AddAll(List l);
}
class List<T> : List {
new Add(T item);
new AddAll<U>(List<U> l) where U : T;
}
Si noti infine il differente approccio Java/C#:
- Le librerie Java forniscono un supporto al problema dell’upcast:
- I metodi sono già predisposti (si veda addAll, che accetta in input una Collection<? extends E>)
- Il cast verso tipi raw è di default supportato (List<?>)
- Le librerie C# non sono pensate per il supporto verso l’upcast:
- I metodi non prevedono naked constraint (AddAll accetta in input solo una List<T>). I naked constraint sembrano più che altro un workaround non dichiarato
- Il cast verso tipi raw è fornito solo se viene fornita un’implementazione non generica della classe (è quindi richiesto l’intervento implementativo dello sviluppatore)
May 5th, 2011 at 18:25
Hey, Struggling to get high quality traffic to convert into real sales and cash? Watch this video; ==> http://100fhm.com . This is gonna blow your mind… Cheers, Clark Ryan
July 27th, 2011 at 20:33
I have a little secret to share. I came across a web page (actually I was invited) and it offers a secret way to get unlimited income and traffic to affiliate links without the need for a website, or practically anything else. There is this underground software that was practically stolen from a guy down in South Africa and this software is going to be quite buzz worthy pretty soon. The reason this software is so secret is due to the fact that if everyone had access to it, it would simply cut down on the amount of money that the rest of us could make. What this software actually does is something that you have never seen before. This software system generates results in as little as 30 seconds, so there’s no waiting around for traffic or to “see if this works”. You’ll want to get in on this as soon as you can so go ahead and check out the info and watch the video -> http://tinyurl.com/chdiscount
August 6th, 2011 at 16:28
This is the perfect way to break down this infomrtoain.