Lic. Esteban César Calabria Mayo del 2008 Constancia para el éxito (Uso de constantes) Lic. Esteban César Calabria Mayo del 2008 Introducción Las constantes son una herramienta soportada por numerosos lenguajes de programación para definir un valor, por ejemplo numérico o string, que no será alterado en ningún momento, y darle un nombre significativo. Por ejemplo const CONST_ACELERACION_GRAVEDAD = 9.8; De ahí en más siempre que desee realizar un cálculo que involucre la aceleración de la gravedad podemos usar el nombre de la constante en lugar del valor numérico. Var Velocidad:real; SegundosTranscurridos:real (…) Velocidad := CONST_ACELERACION_GRAVEDAD * SegundosTranscurridos; (…) En esta ocasión aprovecharé la oportunidad para hablar sobre el uso de las constantes y por qué se suele recomendar tanto su uso. Daremos al final algunos ejemplos de como utilizarlas en distintos lenguajes. Este trabajo se divide en dos. La primera parte aboga el uso de la constantes explicando en que nos benefician. Si el lector se siente cómodo y está familiarizado con su uso puede ir directamente a la segunda parte donde se dan ejemplos de cómo aplicarlas en distintos lenguajes. Parte 1. – Sobre el uso de las constantes 1.1.Facilitar la lectura del código La mayoría de las personas no poseemos la habilidad natural que poseen las computadoras para trabajar con números. Para comunicarnos utilizamos palabras y no una interminable secuencia de bits. Es por ello que un programa cuanto más cercano está al lenguaje de la computadora menos inteligible es para una persona. Cuando en el cuerpo de algún método aparece un valor numérico distinto a 0, 1, -1 o un string literal diremos que estamos en presencia de un valor hardcodeado. 1 Lic. Esteban César Calabria Mayo del 2008 Velocidad := 9.8 * SegundosTranscurridos; (Ej. Valor Hardcodeado) Los valores hardcodeados generalmente representan algo, la aceleración de la gravedad, el porcentaje de iva, etc. No obstante para entender su significado hay que tener el nivel de familiarización con el código que tiene el programador que acaba de escribirlo. Si otra persona, o el mismo programador, un tiempo después se cruzan con el valor hardcodeado requiere de un esfuerzo de interpretación para saber a que se refería ese valor originalmente. Si reemplazáramos ese valor hardcodeado por una constante y a la misma se le diera un nombre lo suficientemente significativo, ese esfuerzo de interpretación se eliminaría facilitando enormemente la legibilidad del código fuente. 1.2.Facilita modificar el código. Hay valores que dependiendo del problema que estamos resolviendo tienen especial importancia. En una aplicación financiera por ejemplo lo es el porcentaje del IVA mientras que en un programa que realiza cálculos físicos tal vez lo sea la aceleración de la gravedad. Esos valores son claves para el problema que estamos resolviendo. Si quisieramos alterar alguno de esos valores, por ejemplo si por una disposición de la AFIP se altera el porcentaje del IVA, tendríamos que recorrer todo el código fuente de nuestra aplicación, buscar donde aparece y reemplazarlo. Con el uso de las constantes esa tarea se nos simplifica ya que nos provee un punto (o varios) conocido y centralizado de nuestro programa donde se agrupan los valores de importancia. Si en algún momento tenemos que modificar alguno de esos valores iremos directamente ahí sin necesidad de recorrer todo el código fuente. Es importante, al igual que las variables, que las constantes posean nombres significativos ya que de nada sirve reemplazar - y hasta puede empeorar las cosas un valor hardcodeado por una constante cuyo nombre no represente nada al que lee el código. 1.3.Evita errores lógicos El caso anterior no sólo nos facilita modificar el código fuente. Volvamos al caso donde la AFIP saca una resolución por la cual se modifica el porcentaje del IVA y por lo tanto tenemos que modificar nuestra aplicación financiera. Habrá que corregir en el código el valor viejo del porcenaje del IVA en todos los lugares que aparezca. 2 Lic. Esteban César Calabria Mayo del 2008 Ahora si por algún motivo dejamos un lugar sin actualizar el nuevo porcenaje del IVA, nuestra aplicación compilará correctamente pero contendrá errores lógicos. Tal vez dicho error sea detectado mucho tiempo después mientras el cliente use la aplicación y se dé cuenta de que los números no le cierran. Esta clase de errores son los más graves con los que podemos encontrarnos. Uno de los objetivos que se persigue a la hora de programar, sobre todo por la razón antes mencionada, es evitar el código duplicado. Podemos decir que tener en dos lados distintos el mismo valor hardcodeado representando la misma cosa, es estar ante la presencia de código duplicado, aunque no se trate de dos fragmentos de código sino simplemente de un valor que debería ser constante. 1.4.Provee una forma de parametrización Una de las características con las que se suele halagar a una aplicación es subrayar su flexibilidad en cuanto a las distintas opciones de parametrización que posee. Esto significa la posibilidad de alterar su comportamiento modificando algún parámetro. Qué es y qué no es un parametro podemos decir que queda en manos del que lo hace, pero como ejemplo podemos citar la posibilidad que nos ofrecen algunos programas de modificar el color de fondo de la aplicación y que la misma siga funcionando. Esto me parece importante porque poniendo los parámetros del sistema como constantes podemos alterar su comportamiento (parametrizarlo) modificandolas y volviendo a recompilar. No obstante en la práctica nos encontramos que la parametrización del sistema se hace dentro del mismo o bien mediante algún archivo de configuración. Esto nos dice algo importante. El uso de constantes como buena práctica va más allá de los beneficios mencionados. Nos habla de separar la lógica de un algoritmo que resuelve un problema de los valores concretos con los que opera. Este principio nos puede ayudar a pensar algoritmos más reutilizables que resuelvan con cierto nivel de abstracción un problema concreto y pueda aplicarse en escenarios diferentes al que se utilizó originalmente. El día de hoy utilizamos constantes, mañana esos valores pueden salir de una base de datos relacional. 1.5. Desventajas Las constantes presentan el inconveniente de requerir el esfuerzo adicional al programador de declararla cada vez que se encuentre con un valor hardcodeado, algo que en el calor de la resolución del problema suele pasar un segundo plano. En ese caso se puede, después de escribir el código, volverlo a leer para asegurarse que no haya algún valor hardcodeado que convenga reemplazarlo por una 3 Lic. Esteban César Calabria Mayo del 2008 constante. De igual forma sigue requeriendo un esfuerzo más de parte del autor del código. Mas aún los entornos de desarrollo actuales no suelen poseer un mecanismo para advertir sobre (y pedirles modificar) la presencia de valores hardcodeados. El programador deberá estar atento, al declarar una constante, que ésta ya no exista con un nombre distinto. Ayudaría si al compilar la aplicación el entorno de desarrollo advirtiera sobre la presencia de distintas constantes con el mismo valor para corroborar que conceptualmente no se tratan de la misma cosa. 1.6. Mejorar código existente El uso de constantes es además uno de los refactorings (métodos concretos para mejorar código fuente existente) más básicos que podemos aplicar y se le suele conocer como “Replace magic number with numeric constant”. Parte 2. – Constantes en la práctica 2.1.Constantes de tipos básicos Veamos un ejemplo de como declarar constantes simples en algunos lenguajes 2.1.1.Ejemplo en Pascal program EjemploConstantes; uses Crt; const CONST_ACELERACION_GRAVEDAD = 9.8; CONST_DOCENA = 12; CONST_MES_ENERO = 'Enero'; //Constante punto flotante //Constante entera //Constante String (…) 2.1.2.Ejemplo en C# class Constantes { public const double gravedad = 9.8; public const int docena = 12; public const string mes_enero = "Enero"; 4 Lic. Esteban César Calabria Mayo del 2008 (…) } (…) 2.2.Arreglos constantes Arreglos(a.k.a Vectores) constantes También es posible declarar vectores constantes como en este ejemplo. Para demostrarlo usaremos un vector constante para convertir números en letras. 2.2.1.Ejemplo en Pascal program NumerosALetras; uses Crt; const CONST_MIN_NUMERO = 1; CONST_MAX_NUMERO = 10; CONST_NUMEROS_A_LETRAS : array [CONST_MIN_NUMERO..CONST_MAX_NUMERO] of string =('uno','dos','tres','cuatro','cinco', 'seis','siete','ocho','nueve','diez'); var Numero:integer; begin Writeln('Ingrese un numero entre ',CONST_MIN_NUMERO,' y ',CONST_MAX_NUMERO); Readln(Numero); if (Numero>=CONST_MIN_NUMERO) and (Numero<=CONST_MAX_NUMERO) then Begin Writeln('En letras es: ',CONST_NUMEROS_A_LETRAS[Numero]) end else Begin Writeln('Fuera de Rango'); end; Readkey; end. 2.2.2.Ejemplo en C# class NumerosALetras { public const int MIN_NUMERO = 1; public const int MAX_NUMERO = 10; static readonly string[] NUMEROS = new string[MAX_NUMERO-MIN_NUMERO+1] {"uno","dos","tres","cuatr","cinco" , "seis","siete","ocho","nueve","diez" }; static void Main(string[] args) { Console.WriteLine("Ingrese un numero entre {0} y {1} ", MIN_NUMERO, MAX_NUMERO); int Numero; int.TryParse(Console.ReadLine(),out Numero); 5 Lic. Esteban César Calabria Mayo del 2008 if ((Numero >= MIN_NUMERO) && (Numero <= MAX_NUMERO)) { Console.WriteLine("En letras es {0}", NUMEROS[Numero-MIN_NUMERO]); } else { Console.WriteLine("Fuera de Rango"); } Console.ReadLine(); } } 2.3 .Registros Constantes Registros (a.k.a structs, estructuras) constantes De igual forma que los arreglos los registros, estructuras o structs como se prefiera llamarle también pueden ser constantes 2.3.1.Ejemplo en Pascal type TPosicion = record x:integer; y:integer; end; const ALTO = 200; ANCHO = 200; CONST_CENTRO : TPosicion = (x:0 ; y:0); CONST_BORDE_SUPERIOR_DERECHO : TPosicion = (x:ANCHO ; y:ALTO); CONST_BORDE_INFERIOR_IZQUIERDO : TPosicion = (x:-ANCHO ; y:-ALTO); 2.3.2.Ejemplo en c# struct Posicion { public int x; public int y; public Posicion(int x,int y) { this.x = x; this.y = y; } } class Constantes { const int alto = 200; const int ancho = 200; public static readonly Posicion Centro = new Posicion (0,0); public static readonly Posicion BordeSuperiorDerecho = new Posicion(ancho, alto); public static readonly Posicion BordeInferiorIzquierdo = new Posicion(-ancho, -alto); } 6 Lic. Esteban César Calabria Mayo del 2008 2.4 Arreglos de Registros constantes Arreglos (a.k.a. vectores) de Registros (a.k.a.structs, estructuras) constantes Por último podemos tener un arreglo de registros que sea constante. 2.4.1 Ejemplo en Pascal type TPlaneta = record Nombre:String; KmDiametro:integer; end; const POS_MAS_CERCANO_AL_SOL = 1; POS_MAS_LEJANO_AL_SOL = 9; CONST_PLANETAS_SISTEMA_SOLAR : array [POS_MAS_CERCANO_AL_SOL..POS_MAS_LEJANO_AL_SOL] of TPlaneta = ((Nombre:'Mercurio'; Diametro:4880), (Nombre:'Venus'; Diametro: 12103), (Nombre:'Tierra'; Diametro:12756), (Nombre:'Marte'; Diametro:6794), (Nombre:'Jupiter'; Diametro:142984), (Nombre:'Saturno'; Diametro:120536), (Nombre:'Urano'; Diametro: 51118), (Nombre:'Neptuno'; Diametro:49532), (Nombre:'Pluton'; Diametro: 2274)); var Numero:integer; begin Writeln('Ingrese un numero de planeta'); Readln(Numero); if (Numero>=POS_MAS_CERCANO_AL_SOL) and (Numero<=POS_MAS_LEJANO_AL_SOL) then Begin Writeln('En planeta ', CONST_PLANETAS_SISTEMA_SOLAR[Numero].Nombre, ' tiene ', CONST_PLANETAS_SISTEMA_SOLAR[Numero].KmDiametro, ' km de diametro.' ); end else Begin Writeln('Te fuiste del sistema solar'); end; Readkey End; 2.4.2. Ejemplo en C# struct Planeta { public string Nombre; public int KmDiametro; public Planeta(String Nombre, int KmDiametro) { this.Nombre = Nombre; this.KmDiametro = KmDiametro; } 7 Lic. Esteban César Calabria Mayo del 2008 } class PlanetasSistemaSolar { public const int MAS_CERCANO_AL_SOL = 1; public const int MAS_LEJANO_AL_SOL = 9; static readonly Planeta[] PlanetasSistemaSolar = new Planeta[MAS_LEJANO_AL_SOL - MAS_CERCANO_AL_SOL + 1] { new Planeta("Mercurio",4880), new Planeta("Venus",12103), new Planeta("Tierra",12756), new Planeta("Marte",6794), new Planeta("Jupiter",142984), new Planeta("Saturno",120536), new Planeta("Urano",51118), new Planeta("Neptuno",49532), new Planeta("Pluton",2274) }; static void Main(string[] args) { Console.WriteLine("Ingrese un numero de planeta"); int Numero; int.TryParse(Console.ReadLine(), out Numero); if ((Numero >= MAS_CERCANO_AL_SOL) && (Numero <= MAS_LEJANO_AL_SOL)) { int PosVector = Numero - MAS_CERCANO_AL_SOL; Console.WriteLine("El planeta {0} tiene {1} Km. de Diametro", PlanetasSistemaSolar[PosVector].Nombre, PlanetasSistemaSolar[PosVector].KmDiametro); } else { Console.WriteLine("Te fuiste del sistema solar"); } Console.ReadLine(); } } 8