Variables locales y valores de retorno por referencia

“… Turn around/Turn around
It’s on the other side
Feel the sound/Feel the sound
It’s coming from deep inside…”
Kansas, “On the Other Side” (1979)

La entrada anterior tenía al principio como objetivo mostrar el uso de las variables locales y valores de retorno por referencia (ref locals and returns), pero a lo largo del camino me fui desviando de ese objetivo inicial, para terminar hablando de otra cosa totalmente diferente. Con esta entrada intento retomar la senda perdida aquella vez y mostrar la utilización de estas novedosas posibilidades que ofrece C#, aparecidas por primera vez en la versión 7.0.

Estas características tienen como objetivo principal el de introducir una semántica de punteros sin que sea necesario recurrir al código no seguro (unsafe code), con la finalidad última de promover ventajas de rendimiento, de manera similar a los parámetros ref de toda la vida. Por ejemplo, suponiendo que dispusiéramos de una estructura de gran tamaño y necesitáramos pasarla a un método como parámetro, la posibilidad de pasar una referencia a la estructura en lugar de la estructura en sí nos permitiría ahorrar tanto en espacio de pila como en el tiempo necesario para la copia. Aquí me he montado un ejemplo rápido, aunque probablemente haría falta una estructura bastante más grande para que la ganancia fuera perceptible:

namespace RefReturnsAndLocals
{
    public struct Point
    {
        public int X, Y, Z;
        public override string ToString() => $"({X}, {Y}, {Z})";
    }

    static class MainClass
    {
        static void Main()
        {
            Point p = new Point { X = 0, Y = 0, Z = 0 };
            Drift(ref p, 100);
            Console.WriteLine(p);
        }

        static void Drift(ref Point point, int steps)
        {
            var rnd = new Random();
            for (int i = 0; i < steps; i++)
            {
                point.X += rnd.Next(-5, 6);
                point.Y += rnd.Next(-5, 6);
                point.Z += rnd.Next(-5, 6);
            }
        }
    }
}

Las referencias locales operan de manera bastante similar a los parámetros ref; por ejemplo, en el método Drift podríamos haber introducido una variable-referencia local, inicializarla para apuntar al mismo sitio al que apunta el parámetro de entrada y utilizarla en los cálculos:

        static void Drift(ref Point point, int steps)
        {
            ref Point p = ref point;
            var rnd = new Random();
            for (int i = 0; i < steps; i++)
            {
                p.X += rnd.Next(-5, 6);
                p.Y += rnd.Next(-5, 6);
                p.Z += rnd.Next(-5, 6);
            }
        }
    }
}

Observe cómo hay que utilizar ref tanto en la declaración de la variable como en la expresión de inicialización. Al declarar una referencia local como ésta, siempre se la debe inicializar; a partir de C# 7.3 (¿se había Ud. dado cuenta de que ya está disponible?), es posible poner una referencia local a “apuntar” a otro objeto del tipo adecuado en cualquier momento posterior a la inicialización.

Dejaré la presentación de los valores de retorno por referencia, que tienen sus propios detalles interesantes, para la próxima entrega. Pero antes de finalizar aquí, vale la pena recordar una vez más que siempre que se trabaja con punteros, los peligros acechan en todo momento. Por ejemplo, quite el prefijo ref en la declaración de esta última versión del método Drift y en la correspondiente llamada; obtendrá un programa que compila, pero no funciona (¿por qué, amigo lector?).


Referencia musical: “On the Other Side” es el primer tema del “Monolith” (1979), el primer disco que mi banda favorita, Kansas, produjo de manera independiente, un derecho que se ganó a pulso después del enorme éxito de sus proyectos anteriores, “Leftoverture” (1976), “Point of Know Return” (1977) y “Two for the Show” (directo, 1978). Si bien ese disco no alcanzó el nivel de los anteriores, todavía tuvo un relativo éxito; algunos de sus temas aún se dejan oír después de casi 40 años, especialmente “On the Other Side” y “People of the South Wind“, dedicada a la tribu aborigen de la que se derivó originalmente el nombre Kansas.

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 *