Covariância e Contravariância em C#, Parte Um
Vou escrever sobre uma série de artigos do Eric Lippert sobre Covariância e Contravariância. Pretendo dividir os artigos em partes como foi feito no original, pra deixar as coisas mais organizadas e fazer mudanças que forem necessárias pra um melhor entendimento.
Nesta primeira parte vamos entender alguns conceitos sobre tipos.
Primeiramente temos que entender que para dois tipos X e Y, pelo menos uma das seguintes afirmações é verdadeira:
X é maior do que Y.
X é menor do que Y.
X é igual a Y.
X não tem nenhuma relação com Y.
Considere uma hierarquia constituída de: Animal, Mamífero, Reptil, Girafa, Tigre, Cobra e Tartaruga, com seus relacionamentos (Mamífero é uma subclasse de Animal, etc). Mamífero é maior do que Girafa, menor que Animal, e, evidentemente, é igual à Mamífero. Mas Mamífero não é nem maior, nem menor, nem igual a Reptil, é apenas diferente.
Imagine que você tenha uma variável, toda variável tem um tipo que lhe é associado. Em runtime você pode armazenar um objeto que é uma instância de um tipo igual ou menor, ou seja, uma variável do tipo Mamífero pode ter uma instância de Girafa armazenados nela, mas não uma Tartaruga.
Esta idéia de armazenamento de um objeto em um local tipado é um exemplo específico de um princípio mais geral chamado de "princípio da substituição". Isto é, em muitos contextos, podemos substituir uma instância de um tipo "menor" por um "maior".
Agora podemos falar de variância. Considere uma "operação", que manipula tipos. Se o resultado da operação aplicada a qualquer X e Y e sempre resulta em dois tipos X' e Y' com o mesmo relacionamento X e Y a operação é considerada covariante. Se a operação inverte a "grandeza" e a "pequeneza" sobre os seus resultados, mas mantém a igualdade e independência, a operação é considerada "contravariante".
Isso é totalmente imaginário e provavelmente não muito claro. Na próxima parte vamos analisar como o C# implementa variância.