DEV Community

Baltasar García Perez-Schofield
Baltasar García Perez-Schofield

Posted on • Updated on

C#: IDE, por favor, no me "ayudes" más... (III)

Como siempre, quiero recordar que los IDE's, sobre todo en aspectos como la refactorización, son una gran ayuda en la programación.

Lo que veremos en este pequeño artículo es cómo el IDE nos pone nerviosos si no utilizamos var. Esta partícula es una simple ayuda al tecleo (teclear menos) en las declaraciones de variables locales, es decir, dentro de un método, como se puede ver en el siguiente esquema.

<lvalue> = <rvalue>
Enter fullscreen mode Exit fullscreen mode

Mientras lvalue es el nombre de una variable cuando la asignamos por primera vez, rvalue es una expresión. Esto quiere decir que puede ser un literal, como 5, "hola", o 3.5; o puede ser el resultado de llamar a un método.

En el siguiente ejemplo podemos ver varias asignaciones:

int x = 0;
const decimal pi = 3.1416;
string nombre = "Baltasar";
int sentidoDeLaVida = 42;
Enter fullscreen mode Exit fullscreen mode

En los ejemplos más arriba, estamos creando una variable y asignándole un valor en el momento. Es muy importante recordar que el tipo del rvalue debe ser el mismo que el tipo del lvalue (al margen de algunas conversiones numéricas implícitas, como de double a int, por ejemplo).

...y a continuación, podemos ver cómo "quedaría" el resultado si utilizaramos var:

var x = 0;
const double pi = 3.1416;
var nombre = "Baltasar";
var sentidoDeLaVida = 42;
Enter fullscreen mode Exit fullscreen mode

No ha cambiado mucho el código. No podemos aplicar var a constantes, eso es verdad. Pero en cuanto al resto, lo que va a hacer el compilador es asignar a cada una de las variables el tipo del rvalue. En este ejemplo, 0 es un int, por lo que el tipo de x será int (si en lugar de 0 tecleáramos 0.0 o 0d, entonces será double, com 0m sería decimal...); como "Baltasar" es una cadena de caracteres, nombre será un string, y en cuanto al sentidoDeLaVida, pues bueno, es 42, por lo que su tipo es int.

Cuando a la derecha del operador de asignación ('=') tenemos un literal, entonces estamos en uno de esos casos "obvios" en los que podemos utilizar var sin miedo. A no ser, claro, que queramos "restringir" el tipo de la variable con respecto al literal.

var y = 0.1;
var z = 0.2;
Enter fullscreen mode Exit fullscreen mode

En este caso, x va a ser una variable double, si queremos que sea un float, entonces tendremos que utilizar el tipo de la variable a la izquierda, o un sufijo de tipo a la derecha.

var y = 0.1f;
float z = 0.2;
Enter fullscreen mode Exit fullscreen mode

Pero ahora veamos un caso en el que no tenemos un literal a la derecha, sino una expresión basada en llamar a un método o propiedad.

class Chart: Control {
    // ...

    void NormalizeData()
    {
        var numValues = this._values.Count;
        var maxValue = this._values.Max();

        // ...
    }
}
Enter fullscreen mode Exit fullscreen mode

¡Rápido! ¿Cuál es el tipo de numValues y de maxValue?

Veamos, en el caso de numValues obtenemos el resultado de la propiedad Count, de un objeto que probablemente es una colección. Es probable, por tanto, que numValues sea de tipo int. En cuanto a maxValue, se trata de el valor máximo de la colección anterior. Puesss... no sé, espera, que me desplazo a la declaración de _values.

class Chart: Control {
    // ...
    private readonly List<int> _values;
}
Enter fullscreen mode Exit fullscreen mode

Ah, bien, entonces maxValue es un int.

¿Qué problema tiene esto?

Pues que utilizando var hemos perdido la posibilidad de reconocer el tipo de la variable de un solo vistazo. Hemos tenido que realizar varias deducciones para llegar a la conclusión buscada en cuanto a los tipos de las variables.

¿Es importante poder reconocer y entender el código de un vistazo? Sí, lo es y mucho. Recordemos que todas las empresas que se dedican a la programación (Microsoft, IBM...), reconocen que los programadores se pasan al menos el 50% del tiempo (cuando este porcentaje no sube al 60 o incluso el 70%), leyendo código. El código sufre de modificaciones contínuas, bien sea por la resolución de bugs o por la adición de nueva funcionalidad.

Sé lo que estás pensando. Sí, hay código que no se modifica: el que no se usa. Si has creado una aplicación de cualquier tipo y no recibes peticiones de ampliación de funcionalidad o de resolución de errores, es que nadie la está usando.

Vale, cerramos el libro gordo de Petete.

En cuanto a Rider, nos subraya las variables locales que no han sido declaradas con var. Pareciera que var es obligatorio. No lo es. Solo es una herramienta.

Pero para ser justos, Rider también nos proporciona una ayuda visual que nos indica precisamente el tipo de la variable en cuestión.

class Chart: Control {
    // ...
    private void NormalizeData()
    {
        var numValues: int = this._values.Count;
        var maxValue: int = this._values.Max();

        // ...
    }
}
Enter fullscreen mode Exit fullscreen mode

¿Soluciona esto el problema? En mi opinión no, o solo parcialmente. Nos lleva la información del tipo a la derecha de la variables, cuando esperamos verlo a la izquierda (históricamente, C comenzó esta "tradición" que ha continuado con C++, Java o C#). Además, no siempre vamos a editar código con Rider. Y en este caso, las ayudas desaparecerán (no es texto, no forman parte del código fuente).

Entonces, ¿cuando es correcto utilizar var? En realidad, es simple: cuando el tipo a la derecha del igual es obvio, o incluso se repite. Veamos unos cuantos casos en el siguiente código de ejemplo.

var sentidoDeLaVida = 42;
var xGap = (int) ( (double) this.GraphWidth / ( numValues + 1 ) );
var valores = new List<int>( numValores );
Enter fullscreen mode Exit fullscreen mode

En realidad, es el último caso del ejemplo más arriba para el que se creó var: para no tener que repetir el tipo de la expresión a la derecha también a la izquierda. En otro caso, sería como aparece a continuación.

List<int>? valores = new List<int>( numValores );
Enter fullscreen mode Exit fullscreen mode

Ese '?' es importante: var siempre asume que la variable siendo declarada (valores, en este caso) siempre es anulable (nullable en inglés). Dicho de otra forma, que a valores se le va a poder asignar null en algún momento de su vida. Si no deseamos esto comportamiento, entonces tendremos que repetir el tipo a la izquierda y a la derecha. Recuerda que en estos casos el código será mucho más flexible si seguimos la costumbre de utilizar una interfaz a la izquierda.

IList<int> valores = new List<int>( numValores );
Enter fullscreen mode Exit fullscreen mode

(Continuará...)

Top comments (0)