Estoy interesado en la idea de C ++, como const
no esa ejecución particular (como desechar const
).
Tomemos, por ejemplo, C #: carece de C ++, como const, y la razón es la habitual: personas y tiempo. Aquí, además, parece que el equipo de C # analizó la ejecución de C ++ de const
CLR de marketing y tuvo suficiente en este punto (vea por qué no hay un método de miembro const en C # y parámetro const ; gracias Svick). Si nos movemos más allá de eso, ¿hay algo más?
¿Hay algo más profundo? Tomemos, por ejemplo, la herencia múltiple: por lo general, se considera difícil de entender (para el usuario) y, por lo tanto, no se agrega al idioma (como el problema del diamante).
¿Hay algo en NATURE de const
que representan un problema de que es mejor para el lenguaje para evitarlo? Algo así como decidir si const
debe ser profundo o poco profundo (tener const
contenedor significa que no puedo agregar un nuevo elemento o alterar elementos existentes también; ¿qué pasa si los elementos son del tipo de referencia)?
ACTUALIZACIÓN : si bien menciono C # y, por lo tanto, hago una perspectiva histórica, estoy interesado en la naturaleza de los posibles problemas del const
lenguaje.
Este no es un desafío de los idiomas. Ignore factores como las tendencias actuales o la popularidad. Solo estoy interesado en cuestiones técnicas. Gracias.
fuente
Respuestas:
Tenga en cuenta que si esto califica para usted, pero en lenguajes funcionales como Standard ML, todo es inmutable de manera predeterminada. La mutación es compatible a través de un
ref
tipo de diferencia genérico . Entonces, unaint
variable es inmutable, y unaref int
variable es un contenedor mutable paraint
s. Básicamente, las variables son variables reales en el sentido matemático (un valor desconocido pero fijo) y lasref
s son "variables" en el sentido de programación imperativo, una celda de memoria en la que se puede escribir y leer. (Me gusta llamarlos asignables ).Creo que el problema
const
es doble. Primero, C ++ carece de recolección de basura, lo cual es necesario para tener estructuras de datos persistentes no triviales .const
debe ser profundo para que tenga sentido, pero tener valores totalmente inmutables en C ++ no es práctico.En segundo lugar, en C ++ debe optar por participar en
const
lugar de rechazarlo. Pero cuando se olvida deconst
algo y luego lo arregla, terminará en la situación de "envenenamiento constante" mencionada en la respuesta de @ RobY, donde elconst
cambio caerá en cascada a lo largo del código. Siconst
fuera el predeterminado, no se encontraría aplicandoconst
retroactivamente. Además, tener que agregar enconst
todas partes agrega mucho ruido al código.Sospecho que los lenguajes principales que siguieron (por ejemplo, Java) fueron fuertemente moldeados por el éxito y la forma de pensar de C y C ++. Caso en cuestión, incluso con la recolección de basura, la mayoría de las API de recolección de idiomas asumen estructuras de datos mutables. El hecho de que todo sea mutable y la inmutabilidad se vea como un caso de esquina habla mucho sobre la mentalidad imperativa detrás de los lenguajes populares.
EDITAR : Después de reflexionar sobre el comentario de Greenoldman, me di cuenta de que
const
no se trata directamente de la inmutabilidad de los datos;const
codifica en el tipo de método si tiene efectos secundarios en la instancia.Es posible usar la mutación para lograr un comportamiento referencialmente transparente . Suponga que tiene una función que, cuando se llama sucesivamente, devuelve valores diferentes, por ejemplo, una función que lee un solo carácter
stdin
. Podríamos usar caché / memorizar los resultados de esta función para producir un flujo de valores referencialmente transparente. La secuencia sería una lista vinculada cuyos nodos llamarán a la función la primera vez que intente recuperar su valor, pero luego almacenar en caché el resultado. Entonces, sistdin
constainsHello, world!
, la primera vez que intente recuperar el valor del primer nodo, leerá unochar
y regresaráH
. Luego continuará regresandoH
sin más llamadas para leer achar
. Del mismo modo, el segundo nodo leería unachar
destdin
la primera vez que intente recuperar su valor, esta vez devuelvee
y almacena en caché ese resultado.Lo interesante aquí es que ha convertido un proceso inherentemente con estado en un objeto que aparentemente no tiene estado. Sin embargo, fue necesario mutar el estado interno del objeto (almacenando en caché los resultados) para lograr esto: la mutación fue un efecto benigno . Es imposible hacer nuestro
CharStream
const
a pesar de que la transmisión se comporta como un valor inmutable. Ahora imagine que hay unaStream
interfaz conconst
métodos y que todas sus funciones esperanconst Streams
. ¡NoCharStream
puedes implementar la interfaz!( EDITAR 2: Aparentemente hay una palabra clave de C ++ llamada
mutable
que nos permitiría hacer trampa y hacerCharStream
const
. Sin embargo, esta escapatoria destruyeconst
las garantías, ahora realmente no puedes estar seguro de que algo no mutará a través de susconst
métodos. Supongo que no es eso malo, ya que debe solicitar explícitamente la escapatoria, pero aún depende completamente del sistema de honor).En segundo lugar, suponga que tiene funciones de orden superior, es decir, puede pasar funciones como argumentos a otras funciones.
const
ness es parte de la firma de una función, por lo que no podrá pasar las noconst
funciones como argumentos a las funciones que esperanconst
funciones. Hacer cumplir ciegamenteconst
aquí conduciría a una pérdida de generalidad.Finalmente, manipular un
const
objeto no garantiza que no esté mutando algún estado externo (estático o global) a sus espaldas, por lo queconst
las garantías no son tan fuertes como parecen inicialmente.Para mí no está claro que codificar la presencia o ausencia de efectos secundarios en el sistema de tipos sea universalmente una buena cosa.
fuente
var
bajo demanda dejaría solo un problema: ¿la profundidad?const
referencia a un noconst
objeto. Aun así, no creo que tenga sentido tener una superficialidadconst
. El objetivoconst
es garantizar que no podrá modificar el objeto a través de esa referencia. No está permitido eludirconst
creando una noconst
referencia, entonces, ¿por qué estaría bien eludirconst
mutando los miembros del objeto?func foo(const String &s)
y esta es una señals
que no se cambiaráfoo
.null
herencia).El principal problema es que los programadores tienden a no usarlo lo suficiente, por lo que cuando llegan a un lugar donde se requiere, o un responsable de mantenimiento más tarde quiere corregir la corrección constante, hay un gran efecto dominó. Todavía puede escribir código inmutable perfectamente bueno sin
const
, su compilador simplemente no lo hará cumplir, y tendrá más dificultades para optimizarlo. Algunas personas prefieren que su compilador no los ayude. No entiendo a esas personas, pero hay muchas.En lenguajes funcionales, casi todo lo es
const
, y ser mutable es la rara excepción, si es que está permitido. Esto tiene varias ventajas, como una concurrencia más fácil y un razonamiento más fácil sobre el estado compartido, pero lleva un tiempo acostumbrarse si viene de un idioma con una cultura mutable. En otras palabras, no quererconst
es un problema de personas, no técnico.fuente
Veo los inconvenientes como:
"envenenamiento const" es un problema cuando una declaración de const puede obligar a una declaración anterior o siguiente a usar const, y eso puede hacer que sus declaraciones anteriores o siguientes usen const, etc. Y si el envenenamiento const fluye a una clase en una biblioteca sobre el que no tienes control, entonces puedes quedarte atrapado en un mal lugar.
No es una garantía absoluta. Por lo general, hay casos en los que la constante solo protege la referencia, pero no puede proteger los valores subyacentes por una razón u otra. Incluso en C, hay casos extremos que const no puede alcanzar, lo que debilita la promesa que ofrece const.
en general, el sentimiento de la industria parece estar alejándose de las fuertes garantías en tiempo de compilación, por mucho consuelo que puedan brindarle a usted y a mí. Así que por la tarde pasé tocando el 66% de mi base de código debido al envenenamiento constante, algunos Python Guy ha lanzado 10 módulos Python perfectamente funcionales, bien diseñados, probados y totalmente funcionales. Y ni siquiera estaba pirateando cuando lo hizo.
Entonces, tal vez la pregunta sea, ¿por qué llevar a cabo una característica potencialmente controvertida que incluso algunos expertos son ambivalentes cuando intentas adoptar tu nuevo lenguaje elegante?
EDITAR: respuesta corta, un nuevo idioma tiene que subir una colina empinada para su adopción. Sus diseñadores realmente necesitan pensar mucho sobre qué características necesita para obtener la adopción. Take Go, por ejemplo. Google truncó brutalmente algunas de las batallas religiosas más profundas al hacer algunas elecciones de diseño de estilo Conan-the-Barbarian, y realmente creo que el lenguaje es mejor para eso, por lo que he visto.
fuente
int *
puntero mutable a valor mutable,int const *
puntero mutable a valorint * const
constante , puntero constante a valor mutable,int const * const
puntero constante a valor constante.const
), por lo tanto, tales "razones" considero irrelevantes (al menos para esta pregunta). Sobre elconst
envenenamiento, ¿puedes dar un ejemplo? Porque AFAIK es la ventaja, pasas algoconst
y debe permanecerconst
.const
problema, sino cambiar el tipo realmente; hagas lo que hagas, siempre será un problema. Considere pasarRichString
, y luego darse cuenta de que es mejor pasarString
.const
. Es demasiado fácil no hacer lasconst
cosas que deberían serconst
porque tienes que optar por él en lugar de salir de él.Hay algunos problemas filosóficos al agregar
const
un idioma. Si declaraconst
a una clase, eso significa que la clase no puede cambiar. Pero una clase es un conjunto de variables junto con métodos (o mutadores). Logramos la abstracción al ocultar el estado de una clase detrás de un conjunto de métodos. Si una clase está diseñada para ocultar el estado, entonces necesita mutadores para cambiar ese estado desde el exterior y ya no lo esconst
. Por lo tanto, solo es posible declararconst
a las clases que son inmutables. Entonces,const
parece posible solo en escenarios donde las clases (o los tipos que desea declararconst
) son triviales ...Entonces, ¿necesitamos de
const
todos modos? No lo creo. Creo que puedes prescindir fácilmenteconst
si tienes un buen diseño. Qué datos necesita y dónde, qué métodos son métodos de datos a datos y qué abstracciones necesita para E / S, red, vista, etc. Luego, naturalmente, divide módulos y clases que se ocupan del estado y tiene métodos y métodos. clases inmutables que no necesitan estado.Creo que la mayoría de los problemas surgen con objetos de datos grandes y gordos que pueden guardarse, transformarse y dibujarse y luego desea pasarlos a un renderizador, por ejemplo. Por lo tanto, no puede copiar el contenido de los datos, porque es demasiado costoso para un gran objeto de datos. Pero tampoco quieres que cambie, así que necesitas algo como
const
piensas. Deje que el compilador descubra sus defectos de diseño. Sin embargo, si divide esos objetos solo en un objeto de datos inmutable e implementa los métodos en el módulo responsable, puede pasar (solo) el puntero y hacer las cosas que desea hacer con los datos al tiempo que garantiza la inmutabilidad.Sé que en C ++ es posible declarar algunos métodos
const
y no declarar otros métodos, porque son mutadores. Y luego, un tiempo después, necesita un caché y luego un getter muta un objeto (porque se carga lentamente) y ya no lo esconst
. Pero ese era el objetivo de esta abstracción, ¿verdad? No sabes qué estado se muta con cada llamada.fuente
const
(en sentido C ++ ) debe definir la interfaz, también para todas las propiedades.