¿Qué problema tiene este código? (II-R)

“Mama always told me not to look into the sights of the sun
But, mama, that’s where the fun is…”
(“Blinded by the light”, The Manfred Mann’s Earth Band, 1976)

Bueno, la respuesta al puzle de ayer ya prácticamente la han dado los que han opinado, así que solo me queda hacer algunas puntualizaciones.

El programa propuesto es un ejemplo de cómo las expresiones lambda pueden acceder a las variables del contexto en el que son definidas. Estas variables se dice que son capturadas por la expresión lambda. Me ha gustado la explicación que ha dado jmservera de por qué el programa, en la versión que se presenta, imprimirá (64, 64, 64, 64, 64, 64) en vez de la secuencia deseada (1, 2, 4, 8, 16, 32). Ciertamente, creo que puede facilitarle bastante a un principiante la comprensión de cómo funciona el mecanismo de captura: está claro que en el primer bucle lo que se hace es definir las funciones lambda, mientras que éstas son llamadas (se ejecutan) en el segundo bucle, cuando la variable capturada (la i del primer bucle) vale 6, puesto que ese bucle ya ha terminado. No obstante, creo sumamente conveniente complementar esa explicación intuitiva con una presentación detallada de cómo el compilador de C# implementa las capturas, algo que no explicaré aquí, sino que me permitiré dirigir al lector a mi libro “C# 3.0 y LINQ“, donde se muestra, con la ayuda de Reflector, cómo esa implementación se lleva a cabo (OJO: en el capítulo “Métodos anónimos”, que antecede al dedicado a las expresiones lambda).

Obsérvese cómo si se introduce en el primer bucle una variable local, como propone Avalon, el codigo funcionará correctamente: cada expresión lambda capturará la copia correspondiente de esa variable. Recuérdese que las variables locales como la j de abajo “nacen” cuando la ejecución entra en el bloque en el que están definidas, y que serán copias diferentes para cada iteración. Otra cosa es que esas variables locales técnicamente mueren al terminar cada una de las iteraciones, pero el mecanismo de captura se encarga de cierta manera de “alargarles la vida” artificialmente (de modo similar a como hacían los soviéticos con los secretarios generales del PCUS :-).

        {
            // Create array of ‘power’ functions
            var powers = Func<int, int>[MAX_POWER];
            for (int i = 0; i < MAX_POWER; i++)
            {
                int j = i;  // variable local que se crea e inicializa
                               // para cada iteración
                powers[j] = x => (int) Math.Round(Math.Pow(x, j));
            }

            // …
        }

Como se habrá dado cuenta el lector, el mecanismo de captura de variables (sumamente útil en la práctica, como creo que se demuestra en mi libro y en muchas otras fuentes) presenta sutilezas que hay que tener bien claras para que no “nos pille el toro”. ¡Queda advertido!


Pop/rock tip: Manfred Mann es un músico sudafricano afincado en Londres que formó parte de la escena del pop/rock desde principios de los ’60. El éxito mundial, sin embargo, no le llegó hasta 1976, gracias a una versión en clave de rock de una balada de Bruce Springsteen que había pasado originalmente desapercibida, “Blinded by the light“. Era la época en que yo seguía fielmente todos los domingos el American Top Forty a través de la emisora WGBS de Miami; actividad que, además del placer que me proporcionaba la música en sí, tenía el sublime atractivo de lo clandestino: al escuchar ese programa yo estaba incurriendo en “diversionismo ideológico”, el término revolucionario con el que se denominaba entonces al consumo de los “productos culturales del enemigo”. ¡La de gilipolleces de que está llena la historia de la humanidad!

Octavio Hernandez

Desarrollador y consultor en tecnologías .NET. Microsoft C# MVP entre 2004 y 2010.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *