Diferencia entre revisiones de «Correctitud de constantes»
m Bot: 8 - Estandarizaciones y otras mejoras automatizadas |
Corrijo ortografía, gramática, estilo y formato; traduzco categorías; retiro plantilla de mantenimiento, traducción revisada; cambios menores |
||
Línea 1: | Línea 1: | ||
⚫ | En [[programación]], la '''correctitud de constantes''' ({{lang-en|const correctness}}) es el tipo de [[correctitud]] que hace referencia a la adecuada declaración de [[Variable (programación)|variables]] u [[Objeto (programación)|objetos]] como [[Objeto inmutable|inmutables]]. El término es mayormente usado en el contexto de [[C (lenguaje de programación)|C]] o [[C++]], y recibe su nombre de la palabra reservada <code>const</code> de estos lenguajes. |
||
{{Revisar traducción}} |
|||
⚫ | El uso de la palabra reservada <code>const</code> indica lo que el programador «debe» hacer, no necesariamente lo que el programador «puede» hacer, pues calificar datos con esta palabra reservada no provoca que se almacenen en un tipo de [[Memoria (informática)|memoria]] de sólo lectura, sino que ordena al [[compilador]] realizar verificaciones sobre el [[Código fuente|código]] en [[tiempo de compilación]] para finalizar con un error el proceso de compilación en el caso de intentar modificar un dato constante. |
||
⚫ | En [[programación]], la '''correctitud de constantes''' (const correctness |
||
⚫ | El hecho de que sea posible modificar datos calificados con <code>const</code> en [[Tiempo de ejecución|tiempo de ejecución]] prueba que estos no se almacenan en memoria de sólo lectura. Para realizar estos cambios en tiempo de ejecución, deben evitarse las verificaciones que el compilador realiza sobre los valores <code>const</code> mediante el uso de [[Conversión de tipos|conversiones de tipo]] o [[Union (programación)|uniones]]. |
||
⚫ | El uso de la palabra reservada <code>const</code> indica lo que el programador |
||
⚫ | El hecho de que sea posible modificar datos calificados con <code>const</code> en [[Tiempo de ejecución|tiempo de ejecución]] prueba que estos no se almacenan en memoria de sólo lectura. Para realizar estos cambios en tiempo de ejecución deben evitarse las verificaciones que el compilador realiza sobre los valores <code>const</code> mediante el uso de [[Conversión de tipos|conversiones de tipo]] o [[Union (programación)| |
||
<source lang=cpp>const int constante = 0; // Valor constante |
<source lang=cpp>const int constante = 0; // Valor constante |
||
Línea 36: | Línea 34: | ||
*u.punteroA_No_Constante = 4;</source> |
*u.punteroA_No_Constante = 4;</source> |
||
Cabe destacar que el compilador puede decidir realizar [[Optimización de software|optimizaciones]] sobre los valores calificados con <code>const</code> |
Cabe destacar que el compilador puede decidir realizar [[Optimización de software|optimizaciones]] sobre los valores calificados con <code>const</code> —como, por ejemplo, utilizar el valor literal en lugar del valor almacenado en la variable—. Esta optimización es conocida como [[propagación de constantes]] y también se aplica sobre los literales de texto <code>const char *</code>; dado que no es posible modificar el valor de un literal, el ejemplo anterior daría lugar a un [[comportamiento no definido]]. |
||
Los [[Método (informática)| |
Los [[Método (informática)|métodos]] no estáticos pueden declararse como <code>const</code>. Al hacerlo el [[This (programación)|puntero <code>this</code>]] dentro del método es de tipo <code>valor_de_retorno const * const</code> en lugar de <code>valor_de_retorno * const</code>. Esto significa que, dentro del método constante, el compilador tratará como error cualquier llamada a otros métodos no constantes o la modificación de cualquier [[Campo (informática)|campo]] del objeto. |
||
En C++ un campo puede ser declarado como [[mutable (Informática)|<code>mutable</code>]], indicando que la anterior restricción no se aplica sobre él |
En C++, un campo puede ser declarado como [[mutable (Informática)|<code>mutable</code>]], indicando que la anterior restricción no se aplica sobre él. En algunos casos, esto puede ser útil, por ejemplo, para [[Caché (informática)|cachear de datos]], [[recuento de referencias|contar referencias]] o [[sincronización de datos|sincronizar datos]]. En estos casos, no se altera el estado lógico del objeto, pero no es físicamente constante porque su representación [[Sistema binario|binaria]] puede cambiar. |
||
== |
== Sintaxis de C y lenguajes derivados == |
||
⚫ | En C y otros lenguajes derivados, todos los tipos de datos |
||
⚫ | En C y otros lenguajes derivados, todos los tipos de datos —incluyendo los definidos por el usuario— pueden ser declarados con <code>const</code>. Una correctitud de constantes dicta que todas las variables u objetos deben ser declarados constantes a no ser que exista intención de modificarlos. Este uso pro-activo de <code>const</code> hace que los valores sean «más fáciles de entender, rastrear y razonar sobre ellos»,<ref>[[Herb Sutter]] y [[Andrei Alexandrescu]] (2005). ''C++ Coding Standards''. p. 30. Boston: Addison Wesley. ISBN 0-321-11358-6</ref> además de mejorar la legibilidad y comprensión del código, facilitando las tareas del equipo encargado del mantenimiento del código, ya que el propio código muestra la intención de uso de cada valor. |
||
⚫ | |||
⚫ | Para tipos de datos simples |
||
⚫ | |||
⚫ | La flexibilidad para situar el calificador <code>const</code> existe por razones históricas |
||
⚫ | Para tipos de datos simples —excepto punteros—, el calificador <code>const</code> puede situarse en ambos lados del tipo —es decir, <code>const char foo = 'a';</code> equivale a <code>char const foo = 'a';</code>—. En algunos [[compilador]]es, usar <code>const</code> en ambos lados del tipo —por ejemplo, <code>const char const</code>— genera una advertencia pero no un error. |
||
⚫ | |||
⚫ | El significado de <code>const</code> es más complicado para [[Puntero (informática)| |
||
⚫ | La flexibilidad para situar el calificador <code>const</code> existe por razones históricas<ref>Preguntas frecuentes sobre C++ por [[Bjarne Stroustrup]] http://www.stroustrup.com/bs_faq2.html#constplacement</ref> —el C y C++ previos a la estandarización imponían pocas, o ninguna regla de ordenación en los calificadores de tipo—. Dado que usar el calificador antes o después del tipo no provoca ambigüedades, se decidió no desarrollar una regla de ordenación para este caso. |
||
⚫ | |||
⚫ | El significado de <code>const</code> es más complicado para [[Puntero (informática)|punteros]] y [[Referencia (informática)|referencias]] —tanto el puntero como el dato apuntado, incluso ambos, pueden ser calificados con <code>const</code>—. Además, la sintaxis puede ser confusa. Pueden declararse punteros constantes que apunten a datos no constantes, o punteros modificables que apunten a datos no modificables, o punteros constantes a valores constantes. No se puede cambiar el dato al que apunta un puntero constante, pero puede modificarse el dato apuntado. Por el contrario, puede modificarse el dato al que apunta un puntero constante —que debe ser un dato del mismo tipo o un tipo convertible al del puntero—, pero no puede modificarse el valor apuntado a través del mismo. Finalmente, puede declararse un puntero constante a un dato constante, pero no puede cambiarse el dato al que apunta ni modificar el valor del dato apuntado a través del mismo. El siguiente ejemplo ilustra estos matices: |
||
<source lang=c> |
<source lang=c> |
||
Línea 72: | Línea 73: | ||
}</source> |
}</source> |
||
Según las convenciones de C para declaraciones, la declaración sigue al uso, por lo que escribir <code>*</code> sobre un puntero indica su desreferenciación. Así pues, en la declaración <code>int *puntero</code>, al desreferenciar el puntero <code>*puntero</code> se obtiene <code>int</code>, mientras que <code>puntero</code> es un puntero a <code>int</code>. En consecuencia <code>const</code> modifica el identificador a su derecha. |
Según las convenciones de C para declaraciones, la declaración sigue al uso, por lo que escribir <code>*</code> sobre un puntero indica su desreferenciación. Así pues, en la declaración <code>int *puntero</code>, al desreferenciar el puntero <code>*puntero</code> se obtiene <code>int</code>, mientras que <code>puntero</code> es un puntero a <code>int</code>. En consecuencia, <code>const</code> modifica el identificador a su derecha. |
||
Sin embargo, las convenciones de C++ asocian el <code>*</code> con el tipo, como en <code>int* puntero</code> y <code>const</code> modifica el tipo a la izquierda. <code>int const * punteroAConstante</code> puede leerse como |
Sin embargo, las convenciones de C++ asocian el <code>*</code> con el tipo, como en <code>int* puntero</code> y <code>const</code> modifica el tipo a la izquierda. <code>int const * punteroAConstante</code> puede leerse como <code>*punteroAConstante</code> es un <code>int const</code> —el valor es constante—, o <code>punteroAConstante</code> es un <code>int const *</code> —el puntero apunta a un entero constante—: |
||
<source lang=c>int *puntero; // *puntero es un valor int |
<source lang=c>int *puntero; // *puntero es un valor int |
||
Línea 85: | Línea 86: | ||
Según la convención de C++ de analizar el tipo, no el valor, la [[rule of thumb|regla general]] es leer la declaración de derecha a izquierda. Así pues, todo lo que quede a la izquierda del [[asterisco]] pertenece al tipo apuntado y aquello a la derecha del mismo pertenece a las propiedades del puntero. En el anterior ejemplo, <code>int const *</code> puede ser interpretado como un puntero de sólo lectura que apunta a un entero de lectura-escritura. |
Según la convención de C++ de analizar el tipo, no el valor, la [[rule of thumb|regla general]] es leer la declaración de derecha a izquierda. Así pues, todo lo que quede a la izquierda del [[asterisco]] pertenece al tipo apuntado y aquello a la derecha del mismo pertenece a las propiedades del puntero. En el anterior ejemplo, <code>int const *</code> puede ser interpretado como un puntero de sólo lectura que apunta a un entero de lectura-escritura. |
||
También está permitido situar <code>const</code> a la izquierda del tipo en C y C++, la siguiente sintaxis: |
También está permitido situar <code>const</code> a la izquierda del tipo en C y C++, como en la siguiente sintaxis: |
||
<source lang="cpp">const int* punteroAConst; // identico a: int const * punteroAConst |
<source lang="cpp">const int* punteroAConst; // identico a: int const * punteroAConst |
||
Línea 97: | Línea 98: | ||
const int* const punteroConstanteAConst;</source> |
const int* const punteroConstanteAConst;</source> |
||
Las [[Referencia (informática)|referencias]] de C++ siguen normas similares. Declarar una referencia <code>const</code> es redundante ya que no es posible hacer que una referencia apunte a otro objeto: |
Las [[Referencia (informática)|referencias]] de C++ siguen normas similares. Declarar una referencia <code>const</code> es redundante, ya que no es posible hacer que una referencia apunte a otro objeto: |
||
<source lang=cpp>int i = 22; |
<source lang=cpp>int i = 22; |
||
int const & referenciaAConst = i; // Correcto |
int const & referenciaAConst = i; // Correcto |
||
int & const referenciaConstante = i; // Error el "const" es redundante</source> |
int & const referenciaConstante = i; // Error, el "const" es redundante</source> |
||
Se pueden obtener declaraciones realmente complicadas usando [[array|vectores]] multidimensionales y referencias |
Se pueden obtener declaraciones realmente complicadas usando [[array|vectores]] multidimensionales y referencias —o punteros— a punteros; sin embargo, estos usos se consideran confusos y propensos a errores; en consecuencia, se aconseja evitarlos o reemplazarlos por estructuras de mayor nivel de [[Abstracción (informática)|abstracción]]. |
||
===Parámetros y variables=== |
=== Parámetros y variables === |
||
⚫ | <code>const</code> puede ser usado tanto en parámetros de función como en variables |
||
⚫ | <code>const</code> puede ser usado tanto en parámetros de función como en variables [[Variable estática|estáticas]] o automáticas, incluyendo globales o locales. La interpretación varía entre usos. Una variable <code>const</code> estática —variable global o variable estática local— es una constante, y debe usarse para representar datos como constantes matemáticas —por ejemplo, <code>const double PI = 3.14159</code>— o parámetros generales en tiempo de compilación. Una variable <code>const</code> automática —variable local no estática— debe ser [[inicialización|inicializada]], aunque puede usarse un valor diferente en cada llamada —por ejemplo, <code>const int x_al_cuadrado = x*x;</code>—. Un parámetro pasado como referencia <code>const</code> indica que el valor referenciado no se modificará, pues forma parte del [[Diseño por contrato (informática)|contrato]]. Por ello, se suele favorecer el uso de <code>const</code> en parámetros pasados por referencia, pero no en los parámetros pasados por valor. |
||
⚫ | |||
⚫ | Para aprovechar el diseño por contrato en tipos definidos por el usuario |
||
⚫ | |||
⚫ | |||
⚫ | Para aprovechar el diseño por contrato en tipos definidos por el usuario —estructuras y clases—, que pueden tener tanto métodos como campos, el programador debe marcar los métodos de instancia como <code>const</code> si no tiene intención de modificar los campos del objeto. Usar el calificador <code>const</code> sobre los métodos de instancia que lo requieran es esencial para cumplir con la correctitud de constantes, aunque este tipo de correctitud no esté disponible en otros lenguajes de [[Programación orientada a objetos|programación orientada a objetos]], como [[Java (lenguaje de programación)|Java]] y [[C Sharp|C#]], en la [[interfaz de línea de comandos|CLI]] de [[Microsoft]], o en las [[Managed Extensions for C++]]. |
||
⚫ | El calificador <code>const</code> aplicado sobre un método de instancia afecta al objeto apuntado por el puntero <code>this</code>, que es un argumento implícito pasado a todos los métodos de instancia. Por lo tanto, los métodos constantes |
||
⚫ | |||
⚫ | El calificador <code>const</code> aplicado sobre un método de instancia afecta al objeto apuntado por el puntero <code>this</code>, que es un argumento implícito pasado a todos los métodos de instancia. Por lo tanto, los métodos constantes son la manera de aplicar la correctitud de constantes al parámetro implícito <code>this</code>. Por ejemplo: |
||
<source lang="cpp">class C |
<source lang="cpp">class C |
||
Línea 135: | Línea 138: | ||
</source> |
</source> |
||
En el ejemplo anterior, el puntero implícito |
En el ejemplo anterior, el puntero implícito <code>this</code> del método <code>Set()</code> tiene el tipo <code>C *const</code>; mientras que el <code>this</code> de <code>Get()</code> es de tipo <code>const C *const</code>, lo cual indica que ese método no puede modificar el objeto mediante el puntero <code>this</code>. |
||
Es posible declarar un método con el mismo nombre pero con diferente calificación <code>const</code> |
Es posible declarar un método con el mismo nombre pero con diferente calificación <code>const</code> —y, posiblemente, diferente uso— para adaptarse a ambos tipos de llamadas. Por ejemplo: |
||
<source lang="cpp"> |
<source lang="cpp"> |
||
Línea 157: | Línea 161: | ||
</source> |
</source> |
||
La calificación <code>const</code> del objeto determina qué versión de <code>MiVector::Get()</code> será llamada y si se obtendrá una referencia que pueda ser modificada o de sólo lectura. |
La calificación <code>const</code> del objeto determina qué versión de <code>MiVector::Get()</code> será llamada, y si se obtendrá una referencia que pueda ser modificada o de sólo lectura. |
||
Técnicamente ambos métodos tienen diferentes [[firma___busca (informática)|firmas]] ya que sus punteros |
Técnicamente, ambos métodos tienen diferentes [[firma___busca (informática)|firmas]], ya que sus punteros <code>this</code> tienen diferentes tipos. Esto permite al compilador escoger el método correcto. |
||
=== Excepciones a la correctitud de constantes === |
|||
Existen varias excepciones a la correctitud de constantes puras en C y C++, principalmente, por [[retrocompatibilidad]] de código. |
|||
Existen varias excepciones a la correctitud de constantes puras en C y C++. Principalmente por [[retrocompatibilidad]] de código. |
|||
La primera excepción, tan sólo aplicable a C++, es el uso de <code>const_cast</code>, que permite eliminar la calificación <code>const</code> de un dato, haciéndolo modificable. |
La primera excepción, tan sólo aplicable a C++, es el uso de <code>const_cast</code>, que permite eliminar la calificación <code>const</code> de un dato, haciéndolo modificable. La necesidad de eliminar la calificación <code>const</code> surge del uso de [[código heredado]], o de [[Biblioteca (informática)|bibliotecas]] que no pueden cambiarse pero que no cumplen con la correctitud de constantes. Por ejemplo: |
||
La necesidad de eliminar la calificación <code>const</code> surge del uso de [[código heredado]] o [[Biblioteca (informática)|librerías]] que no pueden ser cambiadas pero que no cumplen con la correctitud de constantes. Por ejemplo: |
|||
<source lang="cpp"> |
<source lang="cpp"> |
||
Línea 183: | Línea 188: | ||
En el ejemplo anterior, si el puntero <code>ptr</code> apunta a una variable global, local, o campo calificado con <code>const</code>, o a un objeto creado dinámicamente mediante <code>new const int<code>, el código sólo será correcto si la función <code>LibraryFunc</code> realmente no modifica el valor apuntado por <code>ptr</code>. |
En el ejemplo anterior, si el puntero <code>ptr</code> apunta a una variable global, local, o campo calificado con <code>const</code>, o a un objeto creado dinámicamente mediante <code>new const int<code>, el código sólo será correcto si la función <code>LibraryFunc</code> realmente no modifica el valor apuntado por <code>ptr</code>. |
||
Existe una excepción{{Citation needed|reason=no está claro por qué es una excepción - podría ser considerado como una característica del lenguaje|date=February 2013}} que se aplica tanto a C como a C++: |
Existe una excepción{{Citation needed|reason=no está claro por qué es una excepción - podría ser considerado como una característica del lenguaje|date=February 2013}} que se aplica tanto a C como a C++: los campos puntero o referencia «ignoran» la calificación <code>const</code> de sus propietarios —es decir, en un objeto constante, todos sus miembros son constantes, excepto en el caso de punteros y referencias—. Considérese el siguiente código: |
||
<source lang="cpp"> |
<source lang="cpp"> |
||
Línea 202: | Línea 207: | ||
</source> |
</source> |
||
Aunque el objeto <code>e</code> pasado a <code>Foo()</code> sea constante, |
Aunque el objeto <code>e</code> pasado a <code>Foo()</code> sea constante, lo que implica que todos sus campos sean constantes, el dato apuntado por <code>e.puntero</code> puede ser modificado pese a que no es adecuado desde el punto de vista de la correctitud de constantes —podría darse el caso de que <code>e</code> fuese propietario del dato apuntado—. |
||
Por este motivo, se ha argumentado que la calificación por defecto para punteros y referencias miembro debe ser una correctitud de constantes más profunda, pudiendo modificar el comportamiento por defecto con el calificador <code>mutable</code> cuando el dato apuntado no pertenezca al objeto contenedor, pero aplicar este cambio crearía problemas de compatibilidad con código existente. |
Por este motivo, se ha argumentado que la calificación por defecto para punteros y referencias miembro debe ser una correctitud de constantes más profunda, pudiendo modificar el comportamiento por defecto con el calificador <code>mutable</code> cuando el dato apuntado no pertenezca al objeto contenedor, pero aplicar este cambio crearía problemas de compatibilidad con código existente. Aun así, esta excepción permanece en C y C++. |
||
La anterior excepción puede ser corregida usando una clase que oculte el puntero tras una interfaz que cumpla con la correctitud de constantes |
La anterior excepción puede ser corregida usando una clase que oculte el puntero tras una interfaz que cumpla con la correctitud de constantes; no obstante, estas clases tampoco soportan las semánticas habituales de copia desde un objeto calificado con <code>const</code> —lo que implica que la clase contenedora tampoco puede ser copiada con las semánticas de copia habituales—, ni permiten que otras excepciones ignoren la correctitud de constantes mediante copia involuntaria o intencionada. |
||
Finalmente, varias funciones en la [[Biblioteca estándar de C|biblioteca estándar de C]] no cumplen con la correctitud de constantes, dado que reciben punteros <code>const</code> a cadenas de caracteres y |
Finalmente, varias funciones en la [[Biblioteca estándar de C|biblioteca estándar de C]] no cumplen con la correctitud de constantes, dado que reciben punteros <code>const</code> a cadenas de caracteres y devuelven un puntero no-<code>const</code> a una parte de la misma cadena. |
||
Algunas [[Implementación|implementaciones]] de la |
Algunas [[Implementación|implementaciones]] de la biblioteca C++ estándar, como la de [[Microsoft]],<ref>[http://msdn.microsoft.com/en-us/library/b34ccac3%28VS.80%29.aspx documentación de strchr de Microsoft]</ref> intentan corregir estas excepciones proporcionando dos versiones de algunas funciones: una versión con <code>const</code>, y otra sin ello. |
||
=== |
=== Correctitud de datos volátiles === |
||
⚫ | |||
⚫ | Este calificador se suele encontrar en código que manipula [[hardware]] directamente |
||
⚫ | |||
⚫ | <code>volatile</code> se puede usar de la misma manera que <code>const</code> en declaraciones de variables, punteros, referencias y métodos |
||
⚫ | |||
⚫ | <code>volatile</code> se puede usar de la misma manera que <code>const</code> en declaraciones de variables, punteros, referencias y métodos. De hecho, <code>volatile</code> es usado en ocasiones para implementar estrategias de diseño por contrato que [[Andrei Alexandrescu]] denomina «correctitud de volátiles»,<ref>[http://www.drdobbs.com/cpp/184403766 "Generic<Programming>: volatile — Multithreaded Programmer's Best Friend Volatile-Correctness or How to Have Your Compiler Detect Race Conditions for You"] por Andrei Alexandrescu en ''[[C/C++ Users Journal]]'' Foro de expertos C++</ref> aunque es mucho menos común que la correctitud de constantes. El calificador <code>volatile</code> también puede ser eliminado mediante <code>const_cast</code>, y puede combinarse con el calificador <code>const</code> como puede verse en este ejemplo: |
||
<source lang="cpp">// Configura una referencia a un registro de hardware de solo lectura |
<source lang="cpp">// Configura una referencia a un registro de hardware de solo lectura |
||
Línea 228: | Línea 234: | ||
Dado que <code>registroDeHardware</code> es <code>volatile</code>, aunque el programador no pueda modificar su valor, no existen garantías de que mantenga los mismos datos en lecturas sucesivas. Las semánticas de esta variable indican que es de sólo lectura pero no inmutable. |
Dado que <code>registroDeHardware</code> es <code>volatile</code>, aunque el programador no pueda modificar su valor, no existen garantías de que mantenga los mismos datos en lecturas sucesivas. Las semánticas de esta variable indican que es de sólo lectura pero no inmutable. |
||
==<code>const</code> e <code>immutable</code> en D== |
== <code>const</code> e <code>immutable</code> en D == |
||
En la segunda versión del [[D (lenguaje de programación)|lenguaje D]] exiten dos [[Palabra reservada|palabras reservadas]] relacionadas con la correctitud de constantes |
En la segunda versión del [[D (lenguaje de programación)|lenguaje D]], exiten dos [[Palabra reservada|palabras reservadas]] relacionadas con la correctitud de constantes:<ref>http://www.digitalmars.com/d/2.0/const-faq.html#const</ref> |
||
⚫ | |||
* la palabra reservada <code>immutable</code> denota un dato que no puede ser modificado a través de ninguna referencia; |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
<source lang = "D">int[] foo = new int[5]; // foo es mutable. |
<source lang = "D">int[] foo = new int[5]; // foo es mutable. |
||
const int[] bar = foo; // bar apunta a foo de manera inmutable. |
const int[] bar = foo; // bar apunta a foo de manera inmutable. |
||
Línea 242: | Línea 252: | ||
int[] mutableNums = nums; // Error: No se puede crear una referencia mutable a un dato inmutable.</source> |
int[] mutableNums = nums; // Error: No se puede crear una referencia mutable a un dato inmutable.</source> |
||
=== Ejemplo de const transitivo en D === |
|||
<source lang = "D">class Foo { |
<source lang = "D">class Foo { |
||
Foo next; |
Foo next; |
||
Línea 253: | Línea 264: | ||
== <code>final</code> en Java == |
== <code>final</code> en Java == |
||
En [[Java (lenguaje de programación)|Java]], el calificador <code>final</code> indica que el campo o variable no es asignable |
En [[Java (lenguaje de programación)|Java]], el calificador <code>final</code> indica que el campo o variable no es asignable. Por ejemplo: |
||
<source lang="java">final int i = 3; |
<source lang="java">final int i = 3; |
||
i = 4; // Error! No se puede modificar un objeto "final"</source> |
i = 4; // Error! No se puede modificar un objeto "final"</source> |
||
Línea 264: | Línea 276: | ||
Respecto a los punteros, una referencia <code>final</code> en Java tiene un significado similar a un puntero constante en C++. |
Respecto a los punteros, una referencia <code>final</code> en Java tiene un significado similar a un puntero constante en C++. |
||
<source lang="cpp">Foo *const bar = direccion_de_memoria; // puntero constante</source> |
<source lang="cpp">Foo *const bar = direccion_de_memoria; // puntero constante</source> |
||
En el ejemplo anterior <code>bar</code> debe ser inicializado en el momento de la declaración y no puede cambiar su valor en adelante, pero el valor al que apunta |
En el ejemplo anterior, <code>bar</code> debe ser inicializado en el momento de la declaración y no puede cambiar su valor en adelante, pero el valor al que apunta sí es modificable. Es decir, <code>*bar = ''valor''</code> es válido, solo que no puede cambiar el lugar al que apunta. Las referencias finales de Java funcionan de la misma manera, con la particularidad de que no es necesario inicializarlas. |
||
Simplemente no puede cambiar el lugar al que apunta. Las referencias finales de Java funcionan de la misma manera con la particularidad de que no es necesario inicializarlas. |
|||
<source lang="java">final Foo i; // una declaracion Java</source> |
<source lang="java">final Foo i; // una declaracion Java</source> |
||
Nótese que Java no usa punteros.<ref>[http://java.sun.com/docs/white/langenv/Simple.doc2.html#4107 No More Pointers in Java]</ref> |
|||
También se puede declarar un puntero a datos de |
También se puede declarar un puntero a datos de sólo lectura en C++. |
||
<source lang="cpp">const Foo *bar;</source> |
<source lang="cpp">const Foo *bar;</source> |
||
En el ejemplo anterior <code>bar</code> puede modificarse para que apunte a cualquier dato de tipo <code>Foo</code>; sin embargo el valor apuntado no podrá ser modificado mediante el puntero <code>bar</code>. No existe un mecanismo equivalente en Java. Así pues tampoco existen métodos <code>const</code>. |
En el ejemplo anterior, <code>bar</code> puede modificarse para que apunte a cualquier dato de tipo <code>Foo</code>; sin embargo el valor apuntado no podrá ser modificado mediante el puntero <code>bar</code>. No existe un mecanismo equivalente en Java. Así pues, tampoco existen métodos <code>const</code>. |
||
No se puede forzar la correctitud de constantes en Java |
No se puede forzar la correctitud de constantes en Java. Sin embargo, definiendo interfaces de sólo lectura a una clase se garantiza que los objetos puedan ser utilizados sin posibilida de modificarlos. El ''[[Framework|framework]]'' de colecciones de Java proporciona mecanismos para crear un [[Adapter (patrón de diseño)|adapador]] sobre una <code>Collection</code> mediante <code>Collections.unmodifiableCollection()</code> y métodos similares. |
||
⚫ | |||
⚫ | El lenguaje Java marca <code>const</code> como palabra reservada —por lo que no puede usarse como nombre de variable—, pero no le asocia semántica alguna. Esta palabra clave fue reservada para desarrollar una extensión del lenguaje Java que incluyese métodos <code>const</code> y punteros a tipos <code>const</code> al estilo C++{{Citation needed|date=February 2011}}. Existe una petición para implementar correctitud de constantes en [[Java Community Process|el Proceso de la Comunidad Java]], pero fue cerrada en 2005 indicando que es imposible implementar dicho cambio de manera que sea retrocompatible.<ref>[http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4211070 Ticket for adding const parameters in Java]</ref> |
||
⚫ | Los métodos en Java pueden ser declarados como |
||
⚫ | |||
⚫ | |||
⚫ | En [[C_Sharp|lenguaje C#]], el calificador <code>readonly</code> tiene el mismo efecto sobre campos que el calificador <code>final</code> de Java y el calificador <code>const</code> de C++; el calificador <code>const</code> en C# tiene un efecto similar al <code>#define</code> de C++. El efecto inhibidor de herencia que Java aplica con el calificador <code>final</code> sobre métodos es equivalente al calificador <code>sealed</code> de C#. |
||
⚫ | |||
⚫ | En C#, el calificador <code>readonly</code> tiene el mismo efecto sobre campos que el calificador <code>final</code> de Java y el calificador <code>const</code> de C++; el calificador <code>const</code> en C# tiene un efecto similar al <code>#define</code> de C++ |
||
El contrario que C++, C# no permite calificar métodos y parámetros con <code>const</code>. Sin embargo también se pueden utilizar parámetros de sólo lectura |
El contrario que C++, C# no permite calificar métodos y parámetros con <code>const</code>. Sin embargo, también se pueden utilizar parámetros de sólo lectura; el [[.NET Framework]] proporciona soporte para convertir colecciones modificables en colecciones inmutables que pueden ser pasadas a métodos y funciones. |
||
==Referencias== |
== Referencias == |
||
{{listaref}} |
{{listaref}} |
||
[[Categoría:Variables (programación)]] |
|||
{{DEFAULTSORT:Const-Correctness}} |
|||
[[Categoría:Lenguaje de programación C]] |
|||
[[Category:C programming language family]] |
|||
[[ |
[[Categoría:Tipos de datos]] |
||
[[Categoría:Artículos con códigos de ejemplo]] |
|||
[[Category:Articles with example C code]] |
|||
[[Category:Articles with example C++ code]] |
|||
[[Category:Programming language topics]] |
Revisión del 09:56 23 ago 2013
En programación, la correctitud de constantes (en inglés: const correctness) es el tipo de correctitud que hace referencia a la adecuada declaración de variables u objetos como inmutables. El término es mayormente usado en el contexto de C o C++, y recibe su nombre de la palabra reservada const
de estos lenguajes.
El uso de la palabra reservada const
indica lo que el programador «debe» hacer, no necesariamente lo que el programador «puede» hacer, pues calificar datos con esta palabra reservada no provoca que se almacenen en un tipo de memoria de sólo lectura, sino que ordena al compilador realizar verificaciones sobre el código en tiempo de compilación para finalizar con un error el proceso de compilación en el caso de intentar modificar un dato constante.
El hecho de que sea posible modificar datos calificados con const
en tiempo de ejecución prueba que estos no se almacenan en memoria de sólo lectura. Para realizar estos cambios en tiempo de ejecución, deben evitarse las verificaciones que el compilador realiza sobre los valores const
mediante el uso de conversiones de tipo o uniones.
const int constante = 0; // Valor constante
// Referencia no constante a un valor constante, sin usar la conversion const_cast seria un error
int &noConstante = const_cast<int &>(constante);
// Mediante la referencia no constante se modifica el valor constante:
noConstante = 1;
// Puntero a no constante apuntando a un valor constante, sin usar la conversion const_cast seria un error
int *punteroANoConstante = const_cast<int *>(&constante);
// Mediante el puntero a no constante se modifica el valor constante:
*punteroA_No_Constante = 2;
// Puntero a no constante apuntando a un valor constante, sin usar la conversion estilo C seria un error
punteroANoConstante = (int *)&constante;
// Mediante el puntero a no constante se modifica el valor constante:
*punteroA_No_Constante = 3;
// Union que contiene puntero a constante y puntero a NO constante
union constanteYMutable
{
const int *punteroAConstante;
int *punteroA_No_Constante;
} u;
// Correcto: Puntero a constante apuntando a un valor constante
u.punteroAConstante = &constante;
// Mediante el otro miembro de la union se modifica el valor constante:
*u.punteroA_No_Constante = 4;
Cabe destacar que el compilador puede decidir realizar optimizaciones sobre los valores calificados con const
—como, por ejemplo, utilizar el valor literal en lugar del valor almacenado en la variable—. Esta optimización es conocida como propagación de constantes y también se aplica sobre los literales de texto const char *
; dado que no es posible modificar el valor de un literal, el ejemplo anterior daría lugar a un comportamiento no definido.
Los métodos no estáticos pueden declararse como const
. Al hacerlo el puntero this
dentro del método es de tipo valor_de_retorno const * const
en lugar de valor_de_retorno * const
. Esto significa que, dentro del método constante, el compilador tratará como error cualquier llamada a otros métodos no constantes o la modificación de cualquier campo del objeto.
En C++, un campo puede ser declarado como mutable
, indicando que la anterior restricción no se aplica sobre él. En algunos casos, esto puede ser útil, por ejemplo, para cachear de datos, contar referencias o sincronizar datos. En estos casos, no se altera el estado lógico del objeto, pero no es físicamente constante porque su representación binaria puede cambiar.
Sintaxis de C y lenguajes derivados
En C y otros lenguajes derivados, todos los tipos de datos —incluyendo los definidos por el usuario— pueden ser declarados con const
. Una correctitud de constantes dicta que todas las variables u objetos deben ser declarados constantes a no ser que exista intención de modificarlos. Este uso pro-activo de const
hace que los valores sean «más fáciles de entender, rastrear y razonar sobre ellos»,[1] además de mejorar la legibilidad y comprensión del código, facilitando las tareas del equipo encargado del mantenimiento del código, ya que el propio código muestra la intención de uso de cada valor.
Tipos de datos simples
Para tipos de datos simples —excepto punteros—, el calificador const
puede situarse en ambos lados del tipo —es decir, const char foo = 'a';
equivale a char const foo = 'a';
—. En algunos compiladores, usar const
en ambos lados del tipo —por ejemplo, const char const
— genera una advertencia pero no un error.
La flexibilidad para situar el calificador const
existe por razones históricas[2] —el C y C++ previos a la estandarización imponían pocas, o ninguna regla de ordenación en los calificadores de tipo—. Dado que usar el calificador antes o después del tipo no provoca ambigüedades, se decidió no desarrollar una regla de ordenación para este caso.
Punteros y referencias
El significado de const
es más complicado para punteros y referencias —tanto el puntero como el dato apuntado, incluso ambos, pueden ser calificados con const
—. Además, la sintaxis puede ser confusa. Pueden declararse punteros constantes que apunten a datos no constantes, o punteros modificables que apunten a datos no modificables, o punteros constantes a valores constantes. No se puede cambiar el dato al que apunta un puntero constante, pero puede modificarse el dato apuntado. Por el contrario, puede modificarse el dato al que apunta un puntero constante —que debe ser un dato del mismo tipo o un tipo convertible al del puntero—, pero no puede modificarse el valor apuntado a través del mismo. Finalmente, puede declararse un puntero constante a un dato constante, pero no puede cambiarse el dato al que apunta ni modificar el valor del dato apuntado a través del mismo. El siguiente ejemplo ilustra estos matices:
void Foo( int * puntero,
int const * punteroAConst,
int * const punteroConstante,
int const * const punteroConstanteAConst )
{
*puntero = 0; // Correcto: modifica el dato apuntado
puntero = NULL; // Correcto: modifica el puntero
*punteroAConst = 0; // Error! No puede modificarse el objeto apuntado
punteroAConst = NULL; // Correcto: modifica el puntero
*punteroConstante = 0; // Correcto: modifica el dato apuntado
punteroConstante = NULL; // Error! No puede modificarse el puntero
*punteroConstanteAConst = 0; // Error! No puede modificarse el objeto apuntado
punteroConstanteAConst = NULL; // Error! No puede modificarse el puntero
}
Según las convenciones de C para declaraciones, la declaración sigue al uso, por lo que escribir *
sobre un puntero indica su desreferenciación. Así pues, en la declaración int *puntero
, al desreferenciar el puntero *puntero
se obtiene int
, mientras que puntero
es un puntero a int
. En consecuencia, const
modifica el identificador a su derecha.
Sin embargo, las convenciones de C++ asocian el *
con el tipo, como en int* puntero
y const
modifica el tipo a la izquierda. int const * punteroAConstante
puede leerse como *punteroAConstante
es un int const
—el valor es constante—, o punteroAConstante
es un int const *
—el puntero apunta a un entero constante—:
int *puntero; // *puntero es un valor int
int const *punteroAConst; // *punteroAConst es constante
int * const punteroConstante; // punteroConstante es constante
int const * const punteroConstanteAConst; // punteroConstanteAConst es constante (puntero)
// y *punteroConstanteAConst es constante (valor)
Según la convención de C++ de analizar el tipo, no el valor, la regla general es leer la declaración de derecha a izquierda. Así pues, todo lo que quede a la izquierda del asterisco pertenece al tipo apuntado y aquello a la derecha del mismo pertenece a las propiedades del puntero. En el anterior ejemplo, int const *
puede ser interpretado como un puntero de sólo lectura que apunta a un entero de lectura-escritura.
También está permitido situar const
a la izquierda del tipo en C y C++, como en la siguiente sintaxis:
const int* punteroAConst; // identico a: int const * punteroAConst
const int* const punteroConstanteAConst; // identico a: int const * const punteroConstanteAConst
Esta notación separa con mayor claridad las dos localizaciones de const
, y permite que el *
siempre se asocie a su tipo precedente, aunque aún necesite ser leído de izquierda a derecha:
int* puntero;
const int* punteroAConst; // (const int)*, no constante (int*)
int* const punteroConstante;
const int* const punteroConstanteAConst;
Las referencias de C++ siguen normas similares. Declarar una referencia const
es redundante, ya que no es posible hacer que una referencia apunte a otro objeto:
int i = 22;
int const & referenciaAConst = i; // Correcto
int & const referenciaConstante = i; // Error, el "const" es redundante
Se pueden obtener declaraciones realmente complicadas usando vectores multidimensionales y referencias —o punteros— a punteros; sin embargo, estos usos se consideran confusos y propensos a errores; en consecuencia, se aconseja evitarlos o reemplazarlos por estructuras de mayor nivel de abstracción.
Parámetros y variables
const
puede ser usado tanto en parámetros de función como en variables estáticas o automáticas, incluyendo globales o locales. La interpretación varía entre usos. Una variable const
estática —variable global o variable estática local— es una constante, y debe usarse para representar datos como constantes matemáticas —por ejemplo, const double PI = 3.14159
— o parámetros generales en tiempo de compilación. Una variable const
automática —variable local no estática— debe ser inicializada, aunque puede usarse un valor diferente en cada llamada —por ejemplo, const int x_al_cuadrado = x*x;
—. Un parámetro pasado como referencia const
indica que el valor referenciado no se modificará, pues forma parte del contrato. Por ello, se suele favorecer el uso de const
en parámetros pasados por referencia, pero no en los parámetros pasados por valor.
Métodos
Para aprovechar el diseño por contrato en tipos definidos por el usuario —estructuras y clases—, que pueden tener tanto métodos como campos, el programador debe marcar los métodos de instancia como const
si no tiene intención de modificar los campos del objeto. Usar el calificador const
sobre los métodos de instancia que lo requieran es esencial para cumplir con la correctitud de constantes, aunque este tipo de correctitud no esté disponible en otros lenguajes de programación orientada a objetos, como Java y C#, en la CLI de Microsoft, o en las Managed Extensions for C++.
Los métodos calificados con const
pueden ser llamados desde objetos constantes y no constantes indistintamente, mientras que los métodos sin calificación const
sólo pueden llamarse desde objetos no constantes.
El calificador const
aplicado sobre un método de instancia afecta al objeto apuntado por el puntero this
, que es un argumento implícito pasado a todos los métodos de instancia. Por lo tanto, los métodos constantes son la manera de aplicar la correctitud de constantes al parámetro implícito this
. Por ejemplo:
class C
{
int i;
public:
int Get() const // Calificado con "const"
{ return i; }
void Set(int j) // Sin calificacion "const"
{ i = j; }
};
void Foo(C& noConstante, const C& constante)
{
int y = noConstante.Get(); // Correcto
int x = constante.Get(); // Correcto: Get() es const
noConstante.Set(10); // Correcto: noConstante es modificable
constante.Set(10); // Error! Set() no es const mientras que constante es un objecto const
}
En el ejemplo anterior, el puntero implícito this
del método Set()
tiene el tipo C *const
; mientras que el this
de Get()
es de tipo const C *const
, lo cual indica que ese método no puede modificar el objeto mediante el puntero this
.
Es posible declarar un método con el mismo nombre pero con diferente calificación const
—y, posiblemente, diferente uso— para adaptarse a ambos tipos de llamadas. Por ejemplo:
class MiVector
{
int data[100];
public:
int & Get(int i) { return data[i]; }
int const & Get(int i) const { return data[i]; }
};
void Foo( MiVector & vectorNoConstante, MiVector const & vectorConstante )
{
// Obtenemos una referencia a un elemento del vector
// y modificamos su valor:
vectorNoConstante.Get( 5 ) = 42; // Correcto! (llama int & MiVector::Get(int))
vectorConstante.Get( 5 ) = 42; // Error! (llama int const & MiVector::Get(int) const)
}
La calificación const
del objeto determina qué versión de MiVector::Get()
será llamada, y si se obtendrá una referencia que pueda ser modificada o de sólo lectura.
Técnicamente, ambos métodos tienen diferentes firmas, ya que sus punteros this
tienen diferentes tipos. Esto permite al compilador escoger el método correcto.
Excepciones a la correctitud de constantes
Existen varias excepciones a la correctitud de constantes puras en C y C++, principalmente, por retrocompatibilidad de código.
La primera excepción, tan sólo aplicable a C++, es el uso de const_cast
, que permite eliminar la calificación const
de un dato, haciéndolo modificable. La necesidad de eliminar la calificación const
surge del uso de código heredado, o de bibliotecas que no pueden cambiarse pero que no cumplen con la correctitud de constantes. Por ejemplo:
// Prototipo de una funcion que no podemos modificar pero que
// sabemos que no modifica los datos apuntados por el puntero.
void LibraryFunc(int *ptr, int size);
void CallLibraryFunc(int const *ptr, int size)
{
LibraryFunc(ptr, size); // Error! ptr es constante
int *nonConstPtr = const_cast<int*>(ptr); // se elimina la calificacion const
LibraryFunc(nonConstPtr, size); // Correcto
}
Sin embargo, el estándar ISO de C++ indica que intentar modificar un objeto calificado con const
a través de const_cast
desemboca en un comportamiento no definido.
En el ejemplo anterior, si el puntero ptr
apunta a una variable global, local, o campo calificado con const
, o a un objeto creado dinámicamente mediante new const int
, el código sólo será correcto si la función
LibraryFunc
realmente no modifica el valor apuntado por ptr
.
Existe una excepción[cita requerida] que se aplica tanto a C como a C++: los campos puntero o referencia «ignoran» la calificación
const
de sus propietarios —es decir, en un objeto constante, todos sus miembros son constantes, excepto en el caso de punteros y referencias—. Considérese el siguiente código:
struct estructura
{
int valor;
int *puntero;
};
void Foo(const estructura & e)
{
int i = 42;
e.valor = i; // Error: e es constante, ergo valor es un entero constante
e.puntero = &i; // Error: e es constante, ergo puntero es un puntero constante a un entero
*e.puntero = i; // Correcto: el dato apuntado por puntero no es constante,
// aunque esto a veces no sea deseable
}
Aunque el objeto e
pasado a Foo()
sea constante, lo que implica que todos sus campos sean constantes, el dato apuntado por e.puntero
puede ser modificado pese a que no es adecuado desde el punto de vista de la correctitud de constantes —podría darse el caso de que e
fuese propietario del dato apuntado—.
Por este motivo, se ha argumentado que la calificación por defecto para punteros y referencias miembro debe ser una correctitud de constantes más profunda, pudiendo modificar el comportamiento por defecto con el calificador mutable
cuando el dato apuntado no pertenezca al objeto contenedor, pero aplicar este cambio crearía problemas de compatibilidad con código existente. Aun así, esta excepción permanece en C y C++.
La anterior excepción puede ser corregida usando una clase que oculte el puntero tras una interfaz que cumpla con la correctitud de constantes; no obstante, estas clases tampoco soportan las semánticas habituales de copia desde un objeto calificado con const
—lo que implica que la clase contenedora tampoco puede ser copiada con las semánticas de copia habituales—, ni permiten que otras excepciones ignoren la correctitud de constantes mediante copia involuntaria o intencionada.
Finalmente, varias funciones en la biblioteca estándar de C no cumplen con la correctitud de constantes, dado que reciben punteros const
a cadenas de caracteres y devuelven un puntero no-const
a una parte de la misma cadena.
Algunas implementaciones de la biblioteca C++ estándar, como la de Microsoft,[3] intentan corregir estas excepciones proporcionando dos versiones de algunas funciones: una versión con const
, y otra sin ello.
Correctitud de datos volátiles
El cualificador volatile
de C y C++ indica que un objeto puede ser cambiado externamente en cualquier momento por medios ajenos al programa y, por lo tanto, debe volverse a leer de la memoria cuando se accede a él.
Este calificador se suele encontrar en código que manipula hardware directamente —en sistemas embebidos y controladores de dispositivos— y en aplicaciones multihilo.
volatile
se puede usar de la misma manera que const
en declaraciones de variables, punteros, referencias y métodos. De hecho, volatile
es usado en ocasiones para implementar estrategias de diseño por contrato que Andrei Alexandrescu denomina «correctitud de volátiles»,[4] aunque es mucho menos común que la correctitud de constantes. El calificador volatile
también puede ser eliminado mediante const_cast
, y puede combinarse con el calificador const
como puede verse en este ejemplo:
// Configura una referencia a un registro de hardware de solo lectura
// que está situado en una posicion de memoria determinada.
const volatile int & registroDeHardware = *reinterpret_cast<int*>(0x8000);
int valorActual = registroDeHardware; // Leemos la memoria
int nuevoValor = registroDeHardware; // Leemos de nuevo
registroDeHardware = 5; // Error! No se puede escribir sobre una variable const
Dado que registroDeHardware
es volatile
, aunque el programador no pueda modificar su valor, no existen garantías de que mantenga los mismos datos en lecturas sucesivas. Las semánticas de esta variable indican que es de sólo lectura pero no inmutable.
const
e immutable
en D
En la segunda versión del lenguaje D, exiten dos palabras reservadas relacionadas con la correctitud de constantes:[5]
- la palabra reservada
immutable
denota un dato que no puede ser modificado a través de ninguna referencia;
- la palabra reservada
const
se refiere a una referencia inmutable de un dato mutable.
Al contrario que el const
de C++, const
e immutable
de D son transitivos, y cualquier dato alcanzable a través de const
o immutable
es const
o immutable
, respectivamente.
Ejemplo de const e immutable en D
int[] foo = new int[5]; // foo es mutable.
const int[] bar = foo; // bar apunta a foo de manera inmutable.
immutable int[] baz = foo; // Error: las referencias a datos inmutables deben ser inmutables.
immutable int[] nums = new immutable(int)[5]; // No se pueden crear referencias mutables a nums
const int[] constNums = nums; // Correcto. immutable se puede convertir implicitamente a const.
int[] mutableNums = nums; // Error: No se puede crear una referencia mutable a un dato inmutable.
Ejemplo de const transitivo en D
class Foo {
Foo next;
int num;
}
immutable Foo foo = new immutable(Foo);
foo.next.num = 5; // Error. foo.next es del tipo immutable(Foo).
// foo.next.num es del tipo immutable(int).
final
en Java
En Java, el calificador final
indica que el campo o variable no es asignable. Por ejemplo:
final int i = 3;
i = 4; // Error! No se puede modificar un objeto "final"
El compilador debe ser capaz de decidir dónde inicializar las variables calificadas con final
, y debe ser inicializada una única vez o la clase no debe compilar. El final
de Java y el const
de C++ tienen el mismo significado al aplicarse sobre tipos básicos.
const int i = 3; // declaracion C++
i = 4; // Error!
Respecto a los punteros, una referencia final
en Java tiene un significado similar a un puntero constante en C++.
Foo *const bar = direccion_de_memoria; // puntero constante
En el ejemplo anterior, bar
debe ser inicializado en el momento de la declaración y no puede cambiar su valor en adelante, pero el valor al que apunta sí es modificable. Es decir, *bar = valor
es válido, solo que no puede cambiar el lugar al que apunta. Las referencias finales de Java funcionan de la misma manera, con la particularidad de que no es necesario inicializarlas.
final Foo i; // una declaracion Java
Nótese que Java no usa punteros.[6]
También se puede declarar un puntero a datos de sólo lectura en C++.
const Foo *bar;
En el ejemplo anterior, bar
puede modificarse para que apunte a cualquier dato de tipo Foo
; sin embargo el valor apuntado no podrá ser modificado mediante el puntero bar
. No existe un mecanismo equivalente en Java. Así pues, tampoco existen métodos const
.
No se puede forzar la correctitud de constantes en Java. Sin embargo, definiendo interfaces de sólo lectura a una clase se garantiza que los objetos puedan ser utilizados sin posibilida de modificarlos. El framework de colecciones de Java proporciona mecanismos para crear un adapador sobre una Collection
mediante Collections.unmodifiableCollection()
y métodos similares.
Los métodos en Java pueden ser declarados como final
, pero este tipo de declaración no tiene relación con la correctitud de constantes sino con la herencia —significa que el método no puede ser sobreescrito en clases derivadas—.
El lenguaje Java marca const
como palabra reservada —por lo que no puede usarse como nombre de variable—, pero no le asocia semántica alguna. Esta palabra clave fue reservada para desarrollar una extensión del lenguaje Java que incluyese métodos const
y punteros a tipos const
al estilo C++[cita requerida]. Existe una petición para implementar correctitud de constantes en el Proceso de la Comunidad Java, pero fue cerrada en 2005 indicando que es imposible implementar dicho cambio de manera que sea retrocompatible.[7]
Código const
y readonly
en C#
En lenguaje C#, el calificador readonly
tiene el mismo efecto sobre campos que el calificador final
de Java y el calificador const
de C++; el calificador const
en C# tiene un efecto similar al #define
de C++. El efecto inhibidor de herencia que Java aplica con el calificador final
sobre métodos es equivalente al calificador sealed
de C#.
El contrario que C++, C# no permite calificar métodos y parámetros con const
. Sin embargo, también se pueden utilizar parámetros de sólo lectura; el .NET Framework proporciona soporte para convertir colecciones modificables en colecciones inmutables que pueden ser pasadas a métodos y funciones.
Referencias
- ↑ Herb Sutter y Andrei Alexandrescu (2005). C++ Coding Standards. p. 30. Boston: Addison Wesley. ISBN 0-321-11358-6
- ↑ Preguntas frecuentes sobre C++ por Bjarne Stroustrup http://www.stroustrup.com/bs_faq2.html#constplacement
- ↑ documentación de strchr de Microsoft
- ↑ "Generic<Programming>: volatile — Multithreaded Programmer's Best Friend Volatile-Correctness or How to Have Your Compiler Detect Race Conditions for You" por Andrei Alexandrescu en C/C++ Users Journal Foro de expertos C++
- ↑ http://www.digitalmars.com/d/2.0/const-faq.html#const
- ↑ No More Pointers in Java
- ↑ Ticket for adding const parameters in Java