¿Alguien me puede explicar el concepto de covarianza y contravarianza en la teoría de los lenguajes de programación ?Covarianza y contravarianza en lenguajes de programación
Respuesta
covarianza es bastante simple y mejor pensamiento desde la perspectiva de alguna clase de colección List
. Podemos parametrizar la clase List
con algún tipo de parámetro T
. Es decir, nuestra lista contiene elementos del tipo T
para algunos T
. Lista se covariante si
S es un subtipo de la lista t si y sólo si [S] es un subtipo de lista [T]
(¿Dónde estoy usando la definición matemática si y sólo si el sentido de si y sólo si.)
es decir, un List[Apple]
es unaList[Fruit]
. Si hay alguna rutina que acepta un List[Fruit]
como parámetro, y tengo un List[Apple]
, entonces puedo pasar esto como un parámetro válido.
def something(l: List[Fruit]) {
l.add(new Pear())
}
Si nuestra clase de colección List
es mutable, a continuación, la covarianza no tiene sentido porque podríamos suponer que nuestra rutina podría añadir alguna otra fruta (que no era una manzana) que el anterior. Por lo tanto, solo nos gustaría que clases de colección inmutables sean covariantes.
buena definición, pero se echa de menos el hecho de que no sólo los tipos pueden ser tratados como co/contravariante Por ejemplo, Java 'List
Creo que 'List extends Fruit> 'es una especie de * tipo existencial *: es decir' List [T] forSome T <: Fruit' - the * forSome T <: Fruit * es en sí mismo un tipo en esta instancia. Sin embargo, Java todavía no es covariante en este tipo. Por ejemplo, un método que acepta una 'Lista extiende Fruit> 'no aceptaría' List ? Extiende Frutas> ' –
quiero decir "no aceptaría un 'Lista
Esta es una buena explicación, no libresca Gracias –
de Heck -.. Incluso disfrutado de su lectura Más de Wikipedia de :) – xtofl
. Bueno, FWIW, la explicación proviene de una discusión que mis colegas y yo tuvimos con un miembro eminente (antiguo HP) cuando la discusión se desvió hacia OOSC por Bertrand Meyers en la que creo que Meyers destaca la importancia de la contravarianza en OOP. Nos dijo OOSC por B.Meyers es una lectura libro si se desea comprender prácticamente POO – Abhay
Aquí están mis artículos sobre cómo hemos añadido nuevas características varianza de C# 4.0. Comienza desde abajo.
http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx
OT: Eric, has publicado un acertijo en una de las preguntas anteriores. No pude resolverlo y le hice preguntas al respecto. ¿Podrías mirarlo? http://stackoverflow.com/questions/1167666/c-puzzle-reachable-goto-pointing-to-an-unreachable-label – SolutionYogi
OMG Eric Lippert !!!! – Janie
Véalo con esos signos de admiración allí. Puedes sacarle el ojo a alguien con una de esas cosas. –
Bart De Smet tiene una gran entrada de blog acerca de covarianza & contravarianza here.
Para mayor comodidad, aquí es una lista ordenada de enlaces a todos los artículos de Eric Lippert en varianza:
- Covariance and Contravariance in C#, Part One
- Covariance and Contravariance in C#, Part Two: Array Covariance
- Covariance and Contravariance in C#, Part Three: Method Group Conversion Variance
- Covariance and Contravariance in C#, Part Four: Real Delegate Variance
- Covariance and Contravariance In C#, Part Five: Higher Order Functions Hurt My Brain
- Covariance and Contravariance in C#, Part Six: Interface Variance
- Covariance and Contravariance in C# Part Seven: Why Do We Need A Syntax At All?
- Covariance and Contravariance in C#, Part Eight: Syntax Options
- Covariance and Contravariance in C#, Part Nine: Breaking Changes
- Covariance and Contravariance in C#, Part Ten: Dealing With Ambiguity
Hay una distinción entre covarianza y contravarianza.
Muy aproximadamente, una operación es covariante si conserva el orden de los tipos, y es contravariante si invierte este orden.
El orden en sí está destinado a representar tipos más generales como más grandes que tipos más específicos.
Aquí hay un ejemplo de una situación en la que C# admite la covarianza. En primer lugar, esto es una matriz de objetos:
object[] objects=new object[3];
objects[0]=new object();
objects[1]="Just a string";
objects[2]=10;
Por supuesto, es posible insertar diferentes valores en la matriz porque al final todos ellos se derivan de System.Object
en marco .NET. En otras palabras, System.Object
es un tipo muy grande o grande. Ahora, aquí hay un punto donde se apoya la covarianza:
la asignación de un valor de un tipo más pequeño de una variable de un tipo más grande
string[] strings=new string[] { "one", "two", "three" };
objects=strings;
Los objetos variables, que es de tipo object[]
, puede almacenar un valor De hecho, es del tipo string[]
.
Piénselo - hasta cierto punto, es lo que espera, pero de nuevo no lo es. Después de todo, mientras string
deriva de object
, string[]
NO deriva de object[]
. El soporte de idiomas para la covarianza en este ejemplo hace que la asignación sea posible de todos modos, que es algo que encontrará en muchos casos. La variación es una función que hace que el lenguaje funcione de manera más intuitiva.
Las consideraciones sobre estos temas son extremadamente complicadas. Por ejemplo, basado en el código anterior, aquí hay dos escenarios que generarán errores.
// Runtime exception here - the array is still of type string[],
// ints can't be inserted
objects[2]=10;
// Compiler error here - covariance support in this scenario only
// covers reference types, and int is a value type
int[] ints=new int[] { 1, 2, 3 };
objects=ints;
Un ejemplo para el funcionamiento de la contravarianza es un poco más complicado.Imagínese estos dos clases:
public partial class Person: IPerson {
public Person() {
}
}
public partial class Woman: Person {
public Woman() {
}
}
Woman
se deriva de Person
, obviamente. Consideremos ahora usted tiene estas dos funciones:
static void WorkWithPerson(Person person) {
}
static void WorkWithWoman(Woman woman) {
}
Una de las funciones hace algo (no importa qué) con un Woman
, el otro es más general y puede trabajar con cualquier tipo derivado de Person
. En el lado Woman
de las cosas, que ahora también tiene estos datos:
delegate void AcceptWomanDelegate(Woman person);
static void DoWork(Woman woman, AcceptWomanDelegate acceptWoman) {
acceptWoman(woman);
}
DoWork
es una función que puede tomar un Woman
y una referencia a una función que también tiene un Woman
, y luego pasa la instancia de Woman
a el delegado Considere el polimorfismo de los elementos que tiene aquí. Person
es mayor de Woman
y WorkWithPerson
es mayor de WorkWithWoman
. WorkWithPerson
también se considera más grande que AcceptWomanDelegate
con el propósito de varianza.
Por último, tienes estas tres líneas de código: Se crea
Woman woman=new Woman();
DoWork(woman, WorkWithWoman);
DoWork(woman, WorkWithPerson);
Un ejemplo Woman
. Luego se llama a DoWork, pasando en la instancia Woman
, así como una referencia al método WorkWithWoman
. El último es obviamente compatible con el tipo de delegado AcceptWomanDelegate
- un parámetro del tipo Woman
, sin tipo de devolución. La tercera línea es un poco extraña, sin embargo. El método WorkWithPerson
toma un Person
como parámetro, no un Woman
, según lo requerido por AcceptWomanDelegate
. Sin embargo, WorkWithPerson
es compatible con el tipo de delegado. Contravarianza lo hace posible, por lo que en el caso de los delegados, el tipo más grande WorkWithPerson
se puede almacenar en una variable del tipo más pequeño AcceptWomanDelegate
. Una vez más es la cosa intuitiva: si WorkWithPerson
puede trabajar con cualquier Person
, pasando en un Woman
no pueden estar equivocados, ¿verdad?
Por ahora, usted puede preguntarse cómo todo esto se relaciona con los genéricos. La respuesta es que la varianza también se puede aplicar a los genéricos. El ejemplo anterior usó matrices object
y string
. Aquí el código utiliza listas genéricas en lugar de las matrices:
List<object> objectList=new List<object>();
List<string> stringList=new List<string>();
objectList=stringList;
Si intenta esto, se dará cuenta de que esto no es un escenario admitido en C#. En C# versión 4.0, así como .NET Framework 4.0, soporte de la varianza en los genéricos ha sido limpiado, y ahora es posible utilizar las nuevas palabras clave en y cabo con parámetros de tipo genérico. Pueden definir y restringir la dirección del flujo de datos para un parámetro de tipo particular, permitiendo que la varianza funcione.Pero en el caso de List<T>
, los datos del tipo T
fluyen en ambas direcciones; hay métodos en el tipo List<T>
que devuelven los valores T
, y otros que reciben dichos valores.
El punto de estas restricciones direccionales es para permitir varianza donde tiene sentido, pero a prevenir problemas como el error de ejecución mencionado en uno de los ejemplos de matriz anteriores. Cuando los parámetros de tipo están decoradas correctamente con en o a cabo, el compilador puede comprobar, y permitir o no, su varianza en tiempo de compilación. Microsoft ha hecho el esfuerzo de añadir estas palabras clave para muchas interfaces estándar en el marco .Net, como IEnumerable<T>
:
public interface IEnumerable<out T>: IEnumerable {
// ...
}
Por esta interfaz, el flujo de datos de tipo T
objetos es clara: pueden ser solamente siempre recuperado de los métodos compatibles con esta interfaz, no pasó a ellos. Como resultado, es posible construir un ejemplo similar al intento List<T>
descrito anteriormente, pero utilizando IEnumerable<T>
:
IEnumerable<object> objectSequence=new List<object>();
IEnumerable<string> stringSequence=new List<string>();
objectSequence=stringSequence;
Este código es aceptable para el compilador de C# desde la versión 4.0 porque IEnumerable<T>
es covariante debido a la cabo especificador en el parámetro de tipo T
.
Al trabajar con tipos genéricos, es importante tener en cuenta la varianza y la forma en que el compilador aplica varios tipos de engaños para hacer que su código funcione de la manera que usted espera.
Hay más información sobre la varianza de la que se trata en este capítulo, pero esto será suficiente para que todos los demás códigos sean comprensibles.
Ref:
Tanto C# y el CLR permite la covarianza y contra-varianza de los tipos de referencia cuando de unión a un método para un delegado. Covarianza significa que un método puede devolver un tipo que es derivado del tipo de devolución del delegado. Contra-varianza significa que un método puede tomar un parámetro que es una base del tipo de parámetro del delegado. Por ejemplo, dado un delegado definido de la siguiente manera:
delegar el objeto MyCallback (FileStream s);
es posible construir una instancia de este tipo de delegado unido a un método que se prototipo
como esto:
cadena SomeMethod (Corriente s);
Aquí, el tipo de devolución de SomeMethod (Serie) es un tipo que se deriva del tipo de devolución del delegado (Objeto); esta covarianza está permitidaEl tipo de parámetro de SomeMethod (Stream) es un tipo que es una clase base del tipo de parámetro del delegado (FileStream); esta contra-varianza está permitida.
Tenga en cuenta que la covarianza y contra-varianza son compatibles sólo para los tipos de referencia, no para los tipos de valor o de vacío. Por lo tanto, por ejemplo, no puedo vincular el siguiente método al delegado de MyCallback:
Int32 SomeOtherMethod (Stream s);
A pesar de que de SomeOtherMethod tipo de retorno (Int32) se deriva de de MyCallback tipo de retorno (Objeto), esta forma de covarianza no está permitido porque Int32 es un tipo de valor.
Obviamente, la razón por la cual los tipos de valor y vacío no se pueden utilizar para covarianza y contra-varianza es debido a que la estructura de memoria para estas cosas varía, mientras que la estructura memoria para los tipos de referencia es siempre un puntero. Afortunadamente, el compilador C# producirá un error si intenta hacer algo que no es compatible.
- 1. .NET: Covarianza y contravarianza
- 2. ¿Demuestra covarianza y contravarianza en Java?
- 3. C# genéricos de lanzamiento (¿covarianza y contravarianza?)
- 4. Covarianza/Contravarianza con una expresión linq
- 5. interfaces de C# Covarianza y contravarianza al implementar
- 6. delegados de acción, los genéricos, covarianza y contravarianza
- 7. ¿Cuáles son los beneficios de la covarianza y la contravarianza?
- 8. C#: ¿Es la varianza (covarianza/contravarianza) otra palabra para polimorfismo?
- 9. covarianza/contravarianza: cómo hacer el siguiente código compilar
- 10. Automóvil Lenguajes de programación
- 11. Convergencia de Matemáticas y Lenguajes de Programación
- 12. Lenguajes de programación SIMD
- 13. Endianness en lenguajes de programación
- 14. gVim y lenguajes de programación múltiples
- 15. jerarquía chomsky y lenguajes de programación
- 16. ¿alguien podría explicar la conexión entre el tipo de covarianza/contravarianza y la teoría de categorías?
- 17. Diferencia entre covarianza y contra varianza
- 18. Diferencia entre covarianza y upcasting
- 19. ¿Lenguajes de programación verdaderamente multilingües?
- 20. lenguajes de programación no determinista
- 21. Frecuencia de símbolos en lenguajes de programación
- 22. Traduciendo Java bytecode en otras representaciones y lenguajes de programación
- 23. Ordenando en lenguajes de programación funcional
- 24. Ejemplos de buenos casos de uso de la vida real para la covarianza y la contravarianza en C# 4.0?
- 25. Covarianza frente a contravarianza con respecto a la herencia de clase
- 26. Covarianza en la programación de nivel de tipo
- 27. Introspección de lenguajes de programación funcional
- 28. Lenguajes de programación administrados de código abierto
- 29. Complejidad de los lenguajes de programación
- 30. ¿Fuente de analizadores para lenguajes de programación?
Huelo una pregunta de tarea. –
[covarianza vs contravarianza] (http://izlooite.blogspot.com/2011/04/covariance-and-contravariance.html) –
posible duplicado de [C#: ¿Es la varianza (covarianza/contravarianza) otra palabra para el polimorfismo?] (http://stackoverflow.com/questions/1078423/c-sharp-is-variance-covariance-contravariance-another-word-for-polymorphis) – nawfal