Colecciones inmutables y por que deben importarme

Los objetos inmutables son aquellos objetos que no pueden cambiar su valor después de creados, en MSDN definen los tipos inmutables como Tipo cuyos datos de instancia (campos y propiedades) no cambian después de crear la instancia. La mayoría de los tipos de valor son inmutables. y pese a que string es un tipo por referencia es el ejemplo mas clásico de inmutabilidad, cuando “reasignamos” un valor a un string NO se modifica como tal, sino que se crea un nuevo string y se apunta a esta nueva ubicación, luego será el GC quien se encargue de limpiar:

            string msj = "Hola mundo";
            msj.Insert(0, "Nicolas "); //Wrong! madafaca
            msj = msj.Insert(0, "Nicolas ");

A diferencia del StringBuilder que es un objeto mutable y podemos modificar su valor sin crear un nuevas copias, algo de la forma: stringBuilder.Add(“Valor”);

Sobre que es mejor (entre mutabilidad e inmutabilidad) como en todos los casos la respuesta es depende, ambos tienen sus propios usos, sus pros y sus contras. Los objetos inmutables aportan una gran utilidad en cuanto a seguridad y simplicidad al trabajar con concurrencia, pero puede resultar costoso implementar objetos muy grandes que deban crear una copia cada vez que se modifique una de sus propiedades. De esto ya hablaremos mas adelante, pero por ahora veo con fascinación el tratamiento que lenguajes funcionales dan toda la importancia a lo valores y no a variables, donde la inmutabilidad es algo que viene de facto y la mutabilidad es algo que hay que hacer especifico.

Read-only no es inmutable

Antes de continuar vale aclarar que: un objeto read-only es un objeto que no expone ninguna forma para cambiarlo, pero nada nos impide realizar cambios de formas que no pertenecen al objeto, es decir, wrappers y demás. El gran Eric Lipter ya habló sobre esto hace unos años, y trata el tema de inmutabilidad superficial e inmutabilidad profunda. Además no son thread safe, que es precisamente una de las ventajas de la inmutabilidad.

Cuando se trabaja con colecciones sabemos que esta el conocido ReadOnlyColletion pero este tiene las mismas desventajas, pese a que es inmutable nada impide que la colección subyacente sufra cambios mientras se hace la lectura de la colección read-only haciendo de esta no thread safe.

¿Como hacen colecciones inmutables sin tamaño fijo?

Muchas colecciones no especializadas utilizan la estructura de datos array, donde su algoritmo de crecimiento es muy sencillo (Si! cuando una colección no tiene un tamaño fijo no es mas que un dynamic array) y para su crecimiento dinámico duplican la capacidad inicial del array incurriendo en un desperdicio de memoria (aunque ni lo notamos). Las colecciones inmútales no se podrían dar este lujo! pues como con los string cualquier “modificación” se traduce en una copia completa del objeto y repuntar esta nueva versión, lo que ocasionaría un crecimiento exponencial en el uso de la memoria. Como no lo tenía tengo muy claro como es que hacen entonces para tener colecciones inmutables sin tamaño fijo, en un tweet pregunté para ver si alguien me daba información, el gran Juanma me colaboro con la respuesta, “usando estructuras enlazadas tipo lista o árbol en lugar de arrays.” Las estructuras de datos persistentes es una estructura de datos que siempre conserva la versión de si mismo cuando este es modificado. Esta estructura de datos es precisamente inmutable. 😀  Y es precisamente la estructura de arboles binarios la que se usa en las colecciones inmutables en .net, pues permiten hacer modificaciones incrementales sin mutar la estructura como tal sino “compartiendo” la memoria entre las dos colecciones resultantes y dejando también una gran responsabilidad al GC para revisar entre las versiones de la colección e intentar recuperar el espacio que lleva algún tiempo asignado pero en desuso, pero como cada mutación creara una nueva versión y compartirá memoria con la anterior supone que el GC se llamara más veces que con una estructura de datos mutable, pues estas referencias podrán ser obsoletas mas pronto cuanto mas veces se actualice la versión de la colección y como debemos saber, para que el GB trabaje obviamente supone  trabajo de computo, memoria y procesador serán empleados mas seguido por el GC dado la naturaleza de esta estructura de datos. Afortunadamente el equipo de MSFT ha ideado una forma de prevenir estas sucesivas recolecciones mejorando muchísimo el performance de estas.

Colecciones inmutables en .NET

El equipo de BCL ha creado para nosotros ya hace unos 7 meses, una implementación de  colecciones inmutables y esta disponible en NuGet las ultimas actualizaciones. Para usarlos solo nos instalamos el paquete “PM> Install-Package Microsoft.Bcl.Immutable –Pre”  y ya podremos hacer uso de System.Collections.Immutable;.

Para crear una nueva colección inmutable basta con acudir al método Create y podremos empezar con una colección vacía o con elementos:

            var empty = ImmutableList.Create();
            var strings = ImmutableList.Create("Colombia", "Venezuela", "Chile");

La edición entonces se hará siempre haciendo una nueva copia de nuestra colección, es decir que si hacemos algo como esto:

            var strings = ImmutableList.Create("Colombia", "Venezuela", "Chile");
            strings.Add("Peru");

Nuestra colección no tendrá el valor “Peru”, para esto debemos emplear un nuevo objeto que contenga dicha copia:

            var strings = ImmutableList.Create("Colombia", "Venezuela", "Chile");
            var conPeru = strings.Add("Peru");

O como con el ejemplo del string.Insert():

            var strings = ImmutableList.Create("Colombia", "Venezuela", "Chile");
            strings = strings.Add("Peru");

Podemos crear una colección inmutable a partir de una colección mutable con el método de extensión ToInmutable…():

            var listamutale = new List {"Colombia", "Venezuela", "Chile"};
            var strings = listamutale.ToImmutableList();

¿Hacer mutable una colección inmutable? si, así como la implementación de StringBuilder tenemos un Builder en las colecciones inmutables que nos permiten hacer un trabajo como cualquier otra colección mutable, luego recuperar su condición de objeto inmutable con el método que señalábamos arriba:

            var strings = ImmutableList.Create("Colombia", "Venezuela", "Chile");
            ImmutableList.Builder mutable = strings.ToBuilder();
            mutable.Add("Peru");
            mutable.Add("Bolivia");

Hay muchísimo mas por hablar sobre la implementación de  colecciones inmutables para .net pero eso ya daría para un post completo. Veamos ahora porque debería importarme.

¿Por que debería importarme?

La mutabilidad da espacio a muchos errores, alteraciones de estado de los objetos, dificultad en la comprobación de valores, dificultad en el trabajo concurrente y demás, son cosas que como usuario de lenguajes imperativos no notamos a la primera, pero que en ocasiones se extrañan. La implementación de colecciones inmutables nos brinda ciertas ventajas frente a todo esto, en aplicaciones WinRT p. ej. con todo su responsive UI y creación de trabajos en segundo plano a partir del uso de TPL que mejor que prevenir excepciones por alteraciones que no logramos prevenir. Si tienes algo que comentar al equipo, este ha abierto varios canales de feedback en busca de una mejora continua.

Hasta el próximo post

Anuncios
Colecciones inmutables y por que deben importarme

Un comentario en “Colecciones inmutables y por que deben importarme

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s