En programación de computadoras , una constante es un valor que no debe ser alterado por el programa durante la ejecución normal, es decir, el valor es constante . [a] Cuando se asocia con un identificador, se dice que una constante es "nombrada", aunque los términos "constante" y "constante nombrada" a menudo se usan indistintamente. Esto se contrasta con una variable , que es un identificador con un valor que se puede cambiar durante la ejecución normal, es decir, el valor es variable. Las constantes son útiles tanto para programadores como para compiladores: para los programadores son una forma de código autodocumentado y permiten razonar sobrecorrección , mientras que para los compiladores permiten verificaciones en tiempo de compilación y tiempo de ejecución que verifican que no se violen los supuestos de constancia, y permiten o simplifican algunas optimizaciones del compilador .
Hay varias realizaciones específicas de la noción general de constante, con sutiles distinciones que a menudo se pasan por alto. Los más importantes son: constantes en tiempo de compilación (valoradas estáticamente), constantes en tiempo de ejecución (valoradas dinámicamente), objetos inmutables y tipos de constantes ( const ).
Los ejemplos típicos de constantes de tiempo de compilación incluyen constantes matemáticas, valores de estándares (aquí unidad de transmisión máxima ) o valores de configuración interna (aquí caracteres por línea ), como estos ejemplos de C:
const float PI = 3,1415927 ; // precisión máxima de un solo flotante const unsigned int MTU = 1500 ; // Ethernet v2, RFC 894 const unsigned int COLUMNS = 80 ;
Los ejemplos típicos de constantes de tiempo de ejecución son valores calculados en función de las entradas a una función, como este ejemplo de C ++:
void f ( std :: string s ) { const size_t l = s . longitud (); // ... }
Usar
Algunos lenguajes de programación hacen una distinción sintáctica explícita entre símbolos de constante y variable, por ejemplo, considerando que la asignación a una constante es un error de sintaxis, mientras que en otros lenguajes se consideran sintácticamente iguales (ambos simplemente un identificador), y la diferencia de tratamiento es semántica (la asignación a un identificador es sintácticamente válida, pero si el identificador es una constante, no es semánticamente inválido).
Un valor constante se define una vez y se puede hacer referencia a él muchas veces a lo largo de un programa. El uso de una constante en lugar de especificar el mismo valor varias veces puede simplificar el mantenimiento del código (como en no repetir ) y puede ser autodocumentado al proporcionar un nombre significativo para un valor, por ejemplo, en PI
lugar de 3.1415926.
Comparación con literales y macros
Hay varias formas principales de expresar un valor de datos que no cambia durante la ejecución del programa y que son consistentes en una amplia variedad de lenguajes de programación. Una forma muy básica es simplemente escribiendo un número literal , carácter o cadena en el código del programa, que es sencillo en C, C ++ y lenguajes similares.
En lenguaje ensamblador, los números y caracteres literales se realizan utilizando las instrucciones de "modo inmediato" disponibles en la mayoría de los microprocesadores. El nombre "inmediato" proviene de que los valores están disponibles inmediatamente en el flujo de instrucciones , en lugar de cargarlos indirectamente buscando una dirección de memoria. [1] Por otro lado, los valores más largos que la longitud de palabra del microprocesador, como cadenas y matrices, se manejan indirectamente y los ensambladores generalmente proporcionan una pseudo-operación de "datos" para incrustar tales tablas de datos en un programa.
Otra forma es definiendo una macro simbólica . Muchos lenguajes de programación de alto nivel y muchos ensambladores ofrecen una función de macro donde el programador puede definir, generalmente al comienzo de un archivo fuente o en un archivo de definición separado, nombres para diferentes valores. Luego, un preprocesador reemplaza estos nombres con los valores apropiados antes de compilar, lo que resulta en algo funcionalmente idéntico al uso de literales, con las ventajas de velocidad del modo inmediato. Debido a que puede ser difícil mantener un código donde todos los valores están escritos literalmente, si un valor se usa de manera repetitiva o no obvia, a menudo se hace como una macro.
Una tercera forma es declarar y definir una variable como "constante". Una variable global o variable estática se pueden declarar (o un símbolo definido en el montaje) con un calificador palabra clave como const
, constant
o final
, lo que significa que su valor se fijará en tiempo de compilación y no debe ser variable en tiempo de ejecución. Los compiladores generalmente colocan constantes estáticas en la sección de texto de un archivo de objeto junto con el código mismo, a diferencia de la sección de datos donde se guardan los datos inicializados no constantes. Algunos compiladores pueden producir una sección dedicada específicamente a las constantes. La protección de la memoria se puede aplicar a esta área para evitar la sobreescritura de tales constantes por punteros errantes.
Estas constantes difieren de los literales de varias formas. Los compiladores generalmente colocan una constante en una única ubicación de memoria identificada por símbolo, en lugar de esparcirse por todo el ejecutable como con una macro. Si bien esto excluye las ventajas de velocidad del modo inmediato, existen ventajas en la eficiencia de la memoria y los depuradores pueden trabajar con estas constantes en tiempo de ejecución. Además, aunque las macros pueden redefinirse accidentalmente por archivos de encabezado en conflicto en C y C ++, las constantes en conflicto se detectan en tiempo de compilación.
Dependiendo del idioma, las constantes se pueden escribir o anular. En C y C ++, las macros proporcionan lo primero, mientras que const
lo último:
#define PI 3.1415926535const float pi2 = 3,1415926535 ;
mientras que en Ada, hay tipos numéricos universales que se pueden usar, si se desea:
pi : constante : = 3,1415926535 ;pi2 : flotación constante : = 3,1415926535 ;
con la variante sin tipo que se convierte implícitamente al tipo apropiado en cada uso. [2]
Constantes valoradas dinámicamente
Además de las constantes estáticas descritas anteriormente, muchos lenguajes procedimentales como Ada y C ++ extienden el concepto de constancia hacia variables globales que se crean en el momento de la inicialización, variables locales que se crean automáticamente en tiempo de ejecución en la pila o en registros, a la memoria asignada dinámicamente que se accede mediante puntero y a listas de parámetros en los encabezados de función.
Las constantes con valores dinámicos no designan una variable como residente en una región específica de la memoria, ni los valores se establecen en el momento de la compilación. En código C ++ como
float func ( const float CUALQUIER COSA ) { const float XYZ = someGlobalVariable * someOtherFunction ( CUALQUIER COSA ); ... }
la expresión a la que se inicializa la constante no son constantes en sí mismas. El uso de la constancia no es necesario aquí para la legalidad del programa o la corrección semántica, pero tiene tres ventajas:
- Está claro para el lector que el objeto no se modificará más, una vez configurado
- Los intentos de cambiar el valor del objeto (por parte de programadores posteriores que no comprenden completamente la lógica del programa) serán rechazados por el compilador.
- El compilador puede realizar optimizaciones de código sabiendo que el valor del objeto no cambiará una vez creado. [3]
Las constantes con valores dinámicos se originaron como una característica del lenguaje con ALGOL 68 . [3] Los estudios de código Ada y C ++ han demostrado que las constantes con valores dinámicos se usan con poca frecuencia, generalmente para el 1% o menos de los objetos, cuando podrían usarse mucho más, como alrededor del 40-50% de los objetos locales que no son de clase. son en realidad invariantes una vez creados. [3] [4] Por otro lado, estas "variables inmutables" tienden a ser las predeterminadas en los lenguajes funcionales, ya que favorecen los estilos de programación sin efectos secundarios (p. Ej., Recursividad) o hacen que la mayoría de las declaraciones sean inmutables de forma predeterminada, como ML . Los lenguajes puramente funcionales incluso prohíben los efectos secundarios por completo.
La constancia se usa a menudo en declaraciones de funciones, como una promesa de que cuando un objeto se pasa por referencia, la función llamada no lo cambiará. Dependiendo de la sintaxis, un puntero o el objeto al que se apunta pueden ser constantes, sin embargo, normalmente se desea este último. Especialmente en C ++ y C, la disciplina de garantizar que las estructuras de datos adecuadas sean constantes en todo el programa se denomina const-correctness .
Parámetros de función constante
En C / C ++, es posible declarar el parámetro de una función o método como constante. Esto es una garantía de que este parámetro no se puede modificar después de la primera asignación (sin darse cuenta). Si el parámetro es un tipo predefinido (integrado), se llama por valor y no se puede modificar. Si es un tipo definido por el usuario, la variable es la dirección del puntero, que tampoco se puede modificar. Sin embargo, el contenido del objeto se puede modificar sin límites. La declaración de parámetros como constantes puede ser una manera de señalizar que este valor debería no ser cambiado, pero el programador debe tener en cuenta que los controles sobre la modificación de un objeto no se puede hacer por el compilador.
Además de esta característica, en C ++ también es posible declarar una función o método como const
. Esto evita que tales funciones o métodos modifiquen cualquier cosa que no sean variables locales.
En C #, la palabra clave const
existe, pero no tiene el mismo efecto para los parámetros de función, como es el caso en C / C ++. Sin embargo, hay una forma de "agitar" al compilador para que realice la comprobación, aunque es un poco complicado. [5]
Para obtener el mismo efecto, primero, se definen dos interfaces
interfaz pública IReadable { IValueInterface aValue { get ; } } interfaz pública IWritable : IReadable { IValueInterface aValue { set ; } }public class AnObject : IWritable { private ConcreteValue _aValue ; public IValueInterface aValue { get { return _aValue ; } establecer { _aValue = valor como ConcreteValue ; } } }
Luego, los métodos definidos seleccionan la interfaz correcta con capacidades de solo lectura o lectura / escritura:
pública vacío doSomething ( IReadable AVariable ) { // No se puede modificar AVariable! }pública vacío doSomethingElse ( IWritable AVariable ) { // se puede modificar AVariable, así que tenga cuidado! }
Constantes orientadas a objetos
Una estructura de datos constante u objeto se denomina " inmutable " en el lenguaje orientado a objetos. El hecho de que un objeto sea inmutable confiere algunas ventajas en el diseño de programas. Por ejemplo, se puede "copiar" simplemente copiando su puntero o referencia, evitando una operación de copia que consume mucho tiempo y conservando memoria.
Los lenguajes orientados a objetos como C ++ amplían la constancia aún más. Los miembros individuales de una estructura o clase pueden convertirse en constantes incluso si la clase no lo es. Por el contrario, la mutable
palabra clave permite cambiar un miembro de la clase incluso si se creó una instancia de un objeto como const
.
Incluso las funciones pueden ser constantes en C ++. El significado aquí es que sólo se puede llamar a una función const para un objeto instanciado como const; una función constante no cambia ningún dato no mutable.
C # tiene tanto const
un readonly
calificador como un ; su const es solo para constantes en tiempo de compilación, mientras que readonly se puede usar en constructores y otras aplicaciones en tiempo de ejecución.
Java
Java tiene un calificador llamado final
que evita cambiar una referencia y se asegura de que nunca apunte a un objeto diferente. Esto no evita cambios en el objeto referido en sí. Java final
es básicamente equivalente a un const
puntero en C ++. No proporciona las otras características de const
.
En Java , el calificador final
indica que el miembro de datos o la variable afectados no se pueden asignar, como se muestra a continuación:
int final i = 3 ; i = 4 ; // ¡Error! No se puede modificar un objeto "final"
Debe ser decidible por los compiladores donde final
se inicializa la variable con el marcador, y debe realizarse solo una vez, o la clase no se compilará. Las palabras clave de Java final
y C ++ const
tienen el mismo significado cuando se aplican con variables primitivas.
const int i = 3 ; // Declaración de C ++ i = 4 ; // ¡Error!
Teniendo en cuenta los punteros, una final
referencia en Java significa algo similar al const
puntero en C ++. En C ++, se puede declarar un "tipo de puntero constante".
Foo * const bar = mem_location ; // tipo de puntero constante
Aquí, bar
debe inicializarse en el momento de la declaración y no se puede volver a cambiar, pero lo que apunta es modificable. Es decir, es válido. Simplemente no puede apuntar a otra ubicación. Las referencias finales en Java funcionan de la misma manera, excepto que pueden declararse no inicializadas.{{{1}}}
final Foo i ; // una declaración de Java
Nota: Java no admite punteros. [6] Esto se debe a que los punteros (con restricciones) son la forma predeterminada de acceder a los objetos en Java, y Java no usa estrellas para indicarlos. Por ejemplo, i en el último ejemplo es un puntero y se puede usar para acceder a la instancia.
También se puede declarar un puntero a datos de "solo lectura" en C ++.
const Foo * bar ;
Aquí bar
se puede modificar para señalar cualquier cosa, en cualquier momento; solo ese valor señalado no se puede modificar a través del bar
puntero.
No existe un mecanismo equivalente en Java. Por tanto, tampoco existen const
métodos. La corrección de la constancia no se puede imponer en Java, aunque mediante el uso de interfaces y la definición de una interfaz de solo lectura para la clase y su transmisión, se puede garantizar que los objetos se puedan pasar por el sistema de una manera que no se puedan modificar.
El marco de las colecciones de Java proporciona una forma de crear una envoltura inmutable de { Collection
via y métodos similares.Collections.unmodifiableCollection()
Un método en Java se puede declarar "final", lo que significa que no se puede anular en subclases.
C#
En C # , el calificador readonly
tiene el mismo efecto en los miembros de datos que final
en Java y const
en C ++; el modificador const
tiene un efecto similar (aunque escrito y de ámbito de clase) al de #define
C ++. El otro efecto inhibidor de la herencia de Java final
cuando se aplica a métodos y clases se induce en C # con la ayuda de la palabra clave sealed
.
A diferencia de C ++, C # no permite que los métodos y parámetros se marquen como const
. Sin embargo, también se pueden pasar subclases de solo lectura, y .NET Framework proporciona cierto soporte para convertir colecciones mutables en inmutables que pueden pasarse como contenedores de solo lectura.
Por paradigma
El tratamiento de las constantes varía significativamente según el paradigma de programación . La corrección constante es un problema en lenguajes imperativos como C ++ porque, de forma predeterminada, los enlaces de nombres suelen crear variables , que pueden variar, como sugiere el nombre, y por lo tanto, si se desea marcar un enlace como constante, esto requiere alguna indicación adicional. [b] En otros lenguajes de programación, surgen problemas relacionados con paradigmas, encontrándose algunos análogos a la const-corrección.
En la programación funcional , los datos suelen ser constantes de forma predeterminada, en lugar de variables de forma predeterminada. En lugar de asignar un valor a una variable (un espacio de almacenamiento con un nombre y un valor potencialmente variable), se crea una vinculación de un nombre a un valor, como por ejemplo mediante la let
construcción en muchos dialectos de Lisp . En algunos lenguajes funcionales, particularmente en los multiparadigmas como Common Lisp , la modificación de datos es algo común, mientras que en otros se evita o se considera excepcional; este es el caso de Scheme (otro dialecto Lisp), que usa la set!
construcción para modificar datos, con la ! signo de exclamación llamando la atención sobre esto. Dichos lenguajes logran los objetivos de corrección constante de forma predeterminada, llamando la atención sobre la modificación en lugar de la constancia.
En varios lenguajes orientados a objetos , existe el concepto de objeto inmutable , que se usa particularmente para tipos básicos como cadenas; los ejemplos notables incluyen Java, JavaScript, Python y C #. Estos lenguajes varían en si los tipos definidos por el usuario pueden marcarse como inmutables y pueden permitir que campos particulares (atributos) de un objeto o tipo se marquen como inmutables.
En algunos lenguajes multiparadigmas que permiten estilos tanto orientados a objetos como funcionales, ambas características pueden combinarse. Por ejemplo, en OCaml, los campos de objeto son inmutables por defecto y deben marcarse explícitamente con la palabra clave mutable
para ser mutables, mientras que en Scala, los enlaces son explícitamente inmutables cuando se definen con val
"valor" y explícitamente mutables cuando se definen con var
"variable".
Convenciones de nombres
Las convenciones de nomenclatura para las constantes varían. Algunos simplemente los nombran como lo harían con cualquier otra variable. Otros usan mayúsculas y guiones bajos para constantes de una manera similar a su uso tradicional para macros simbólicas, como SOME_CONSTANT
. [7] En notación húngara , un prefijo "k" significa tanto constantes como macros y tipos enumerados .
Una convención impuesta es que en Ruby , cualquier variable que comience con una letra mayúscula se considera una constante, incluidos los nombres de clase.
Ver también
- Las constantes de dirección para el IBM / 360 y Z / Arquitectura plataforma
Notas
- ^ En algunos casos, la expectativa de constancia se puede eludir, por ejemplo, utilizando un código de modificación automática o sobrescribiendo la ubicación de la memoria donde se almacena el valor.
- ^ Esto no es universal: en Ada, los parámetros de entrada y los parámetros de bucle son implícitamente constantes, por ejemplo.
Referencias
- ^ Ej. Información de sistemas IBM . Conjunto de instrucciones: referencia del lenguaje ensamblador para PowerPC.
- ^ Booch, Grady (1983). Ingeniería de software con Ada . Benjamin Cummings . págs. 116-117 . ISBN 0-8053-0600-5.
- ^ a b c Schilling, Jonathan L. (abril de 1995). "Constantes de valor dinámico: una característica del lenguaje infrautilizado". Avisos SIGPLAN . 30 (4): 13-20. doi : 10.1145 / 202176.202177 .
- ^ Perkins, JA Programming Practices: Análisis de Ada Source desarrollado para la Fuerza Aérea, el Ejército y la Armada . Actas TRI-Ada '89. págs. 342–354. doi : 10.1145 / 74261.74287 .
- ^ Timwi (9 de septiembre de 2010). "Parámetros de función de sólo lectura (como" const ") de C #" . https://stackoverflow.com/ : Stack Overflow . Consultado el 6 de mayo de 2012 .
[...] Luego puede declarar métodos cuyo tipo de parámetro "dice" si planea cambiar la variable o no :. [...] Esto imita las comprobaciones en tiempo de compilación similares a la constness en C ++. Como señaló correctamente Eric Lippert, esto no es lo mismo que inmutabilidad. Pero como programador de C ++, creo que lo sabes.
- ^ "Red de tecnología de Oracle para desarrolladores de Java | Red de tecnología de Oracle | Oracle" . Java.sun.com. 2013-08-14 . Consultado el 18 de agosto de 2013 .
- ^ Desarrollador de Microsoft Office XP: Nombres constantes