Blog de Fernando Machado Piriz

Artículos sobre transformación digital, arquitectura empresarial y temas relacionados

Archive for abril 2010

¡Run 2.0 en vivo!

leave a comment »

RUN 2.0 en alta definición en esta URL, usando Silverlight 4 Live Smooth Streaming: http://www.dominiodigitalhd.com.ar/dd/bbb/default.html

Anuncios

Written by fmachadopiriz

14/04/2010 at 08:38

Publicado en Anuncios

La explicación fácil para entender covarianza y contravarianza

with 15 comments

Una de las novedades más importantes de C#4.0 y .NET Framework 4.0 es la introducción de covarianza y contravarianza. Varias veces he presentado covarianza y contravarianza en las charlas de novedades de C# y .NET Framework 4.0, y también en el blog, pero no siento que toda la audiencia termine entendiendo fácilmente estos conceptos. Hasta ahora he partido de las definiciones formales de covarianza y varianza, para luego mostrar cómo se implementan en C#. Probablemente no sea el mejor enfoque, así que ahora voy a intentar explicar estos conceptos de otra manera. Aquí vamos.

Vean las siguientes clases Animal y Cat que desciende de Animal:

class Animal { }
class Cat : Animal { }

Las siguientes declaraciones son correctas en cualquier versión de C#:

Cat kitty = new Cat();
Animal animal = kitty;

Todo Cat es un Animal (eso es lo que significa que Cat hereda de Animal), por lo tanto puedo asignar la variable kitty a la variable animal. Hasta ahora no hay nada nuevo.

Vean ahora lo que sucede cuando intento hacer algo análogo con enumerables de Animal y Cat:

IEnumerable<Cat> cats = new List<Cat>();
IEnumerable<Animal> animals = cats;

Todo Cat es un Animal, por lo que intuitivamente todo enumerable de Cat es un enumerable de Animal, ¿cierto? No, falso, al menos para los compiladores anteriores a C# 4.0, que dicen que no pueden convertir IEnumerable<Cat> en IEnumerable<Animal> y me preguntan si me estará faltando un cast.

clip_image001

Puedo agregar el cast, pero es un cast inseguro. Es decir, el programa compila, pero en tiempo de ejecución veo una excepción InvalidCastException en el momento de la asignación.

Ahora bien, coincidamos que a pesar que el compilador de C# no acepte que una todo enumerable de Cat es un enumerable de Animal, intuitivamente aceptamos la afirmación, en forma análoga a la afirmación todo Cat es un Animal.

C# 4.0 resuelve el conflicto. El fragmento de código anterior compila y no genera ninguna excepción en tiempo de ejecución, tal como nuestra intuición nos indica.

¿Por qué el mismo código que compila en C# 4.0 no compila en los anteriores?

Antes de C# 4.0 la interfaz IEnumerable estaba declarada como:

public interface IEnumerable<T> : IEnumerable
{
    IEnumerator<T> GetEnumerator();
}

Mientras que en C# 4.0 está declarada como:

public interface IEnumerable<out T> : IEnumerable
{
    IEnumerator<T> GetEnumerator();
}

Noten la palabra clave out junto al tipo parámetro T: sirve para indicar que la interfaz IEnumerable es covariante con respecto de T. En general, dado S<T>, la covarianza de S respecto de T implica que si la asignación de Y ← X es válida cuando X hereda de Y, entonces la asignación S<Y> ← S<X> también es válida.

Veamos ahora otro fragmento de código que involucra acciones (las acciones son delegados a funciones de la forma void Action<T>(T)) sobre Animal y Cat:

Action<Animal> doToAnimal =
    target => { Console.WriteLine(target.GetType()); };
Action<Cat> doToCat = doToAnimal;
doToCat(new Cat());

De nuevo, como todo Cat es un Animal, una Action<Animal> que puedo hacer con un Animal debería ser también una Action<Cat> que pueda hacer con un Cat. Vean que aunque la afirmación resulta razonable al decirla, los tipos parámetro están al revés que en el caso anterior: allá estaba asignando un enumerable definido en función de un Cat a un enumerable definido en función de un Animal, mientras que aquí estoy asignando una acción definida en función de Animal a una acción definida en función de Cat.

A pesar que la afirmación es razonable, a los compiladores anteriores a C# 4.0 no les gusta la asignación y arrojan al compilar un mensaje similar al del caso anterior: no se puede convertir una Action<Animal> en una Action<Cat>; en esta oportunidad no me pregunta si me está faltando un cast.

clip_image002

Nuevamente C# 4.0 resuelve el problema, y el código anterior sí compila. Veamos cómo están declaradas las acciones.

Antes de C# 4.0 el delegado Action estaba declarado como

public delegate void Action<T>(T obj)

Mientras que ahora en C# 4.0 está declarado así:

public delegate void Action<in T>(T obj)

Noten ahora la palabra clave in junto al tipo parámetro T: sirve para indicar que el delegado Action es contravariante con respecto de T. En general, dados S<T>, la contravarianza implica que si la asignación de Y ← X es válida cuando X hereda de Y, entonces la asignación S<X> ← S<Y> también es correcta.

En resumen, la covarianza en C# 4.0 permite que un método tenga un resultado de un tipo derivado del tipo definido como parámetro de un tipo genérico. De esta forma, permite asignaciones de tipos genéricos que siendo intuitivas, no eran posibles antes, tales como IEnumerable<Animal> IEnumerable<Cat>, cuando Cat hereda de Animal. Noten que IEnumerable sólo puede retornar instancias de T como resultado, no recibe instancias de T como parámetro. Por ello la palabra clave para declarar que IEnumerable es covariante respecto de T es out.

En forma análoga, la contravarianza permite que un método tenga argumentos de un tipo ancestro del tipo especificado como parámetro del tipo genérico. Así, permite también asignaciones que siendo razonables, no eran posibles, como por ejemplo Action<Cat>Action<Animal>. Vean que en este caso Action sólo puede recibir instancias, no las retorna. Por eso la palabra clave para declarar Action contravariante respecto de T es in.

En este artículo estoy mostrando un ejemplo de covarianza con una interfaz genérica y de contravarianza con un delegado genérico (con tipos parámetro); en un próximo artículo les mostraré otros ejemplos diferentes y les contaré que interfaces y delegados del .NET Framwork 4.0 son covariantes o contravariantes.

De aquí pueden descargar el código de ejemplo.

Para probarlo en compiladores anteriores a C# 4.0 y ver la diferencia, cambien el framework para el cual generan en las propiedades del proyecto:

clip_image003

Nos vemos en la próxima.

Written by fmachadopiriz

13/04/2010 at 08:42

Run 2.0

leave a comment »

El próximo miércoles 14 de abril a partir de las 9:00, en la Torre de las Comunicaciones de Antel, tendrá lugar el Run 2.0. Este evento se ha convertido en el más importante del año en material de tecnologías Microsoft. Los lanzamiento más importantes de los últimos tiempos tendrán lugar en el Run 2.0: Visual Studio 2010, .NET Framework 4.0, etc.

Run2.0

En esta oportunidad estaré presentado durante el keynote de la mañana cómo Visual Studio 2010 y el .NET Framework 4.0 ayudan a aumentar la productividad.

En la tarde estaremos junto a Gastón Milano, Gustavo Quintana y David Gorena, en la sesión plenaria para desarrolladores, hablando de las novedades de Visual Studio 2010 y .NET Framework 4.0. Una hora y media de pocos slides y muchas demos.

Pueden registrarse aquí. ¡Los esperamos!

Written by fmachadopiriz

11/04/2010 at 11:47

Publicado en Anuncios

Un nuevo hogar para un viejo blog

leave a comment »

¡Hola! Este es mi primer post en este nuevo sitio. Aquí pueden encontrar los artículos anteriores.

foto

Written by fmachadopiriz

11/04/2010 at 11:20

Publicado en Anuncios