La inmutabilidad ha sido bien entendida por algún tiempo. Python, Java y C ++ tienen diferentes modelos de memoria que dificultan las comparaciones directas. El autor del artículo que citó originalmente no parece conocer C ++.
Al igual que en Python, Java y la mayoría de los lenguajes de paradigmas múltiples, C y C ++ permiten la mutabilidad de forma predeterminada. Esto es lo que los programadores suelen querer: si tengo una String x
variable, quiero poder asignar un nuevo valor x = "foo"
.
El sistema const en C y C ++ permite una gran cantidad de inmutabilidad matizada que falta en Python, Java e incluso Scala. Si una función C ++ toma a const std::string&
o a const char*
, promete (y el compilador se asegura, hasta cierto punto), que esta función no cambiará (¡no puede!) El contenido de esa cadena. Dado un objeto const, solo podemos invocar métodos de ese objeto que también están marcados como const. Si una clase C ++ solo tiene miembros públicos const
, entonces el objeto es efectivamente inmutable.
Sin embargo, esto a veces es confuso ya que en C y C ++ los objetos son ubicaciones de memoria y las variables son nombres para ubicaciones de memoria. Por el contrario, las variables en Python y Java son nombres para punteros a objetos. En un lenguaje con semántica de referencia, x = y
significa "hacer que x apunte al mismo objeto que y". Como solo estamos copiando punteros, esto es posible con objetos inmutables. En un lenguaje con semántica de valor como C ++, significa "actualizar el contenido de x
con el contenido de y
". Por lo tanto, si se desea la reasignación de una variable en C o C ++, la variable puede no tener un tipo constante. Para hacer esto con objetos inmutables, tendríamos que usar un puntero explícitamente.
Que Java y Python utilicen objetos de cadena inmutables es una decisión de diseño fundamental, pero no está directamente relacionado con los beneficios de la inmutabilidad en un entorno de subprocesos múltiples. Una razón es que los literales de cadena en el código fuente se pueden agrupar, lo que reduce la cantidad de objetos. Esto también es posible en C / C ++. En C ++, el literal "foo"
tiene tipo const char[4]
(el cuarto carácter es la terminación '\0'
). Otra razón es que las entradas en conjuntos y claves en dictos / mapas no deben cambiarse. Dado que las cadenas se usan de forma generalizada como claves dict (la mayoría de los objetos de Python son un dict), la inmutabilidad elimina una fuente común de errores. En Java, otra razón para las cadenas inmutables es el modelo de seguridad de Java. Todas estas razones no tienen ninguna relación con el subprocesamiento múltiple.
Si Java se construyera con la inmutabilidad en mente, el lenguaje habría tenido un aspecto muy diferente. Si bien está inspirado en C ++, los diseñadores se esforzaron por crear un lenguaje mucho más simple, deshacerse de la constante es uno de esos pasos. Lo equivalente de Java a una referencia constante de C ++ es un adaptador o decorador que implementa cualquier método de mutación como throws new NotImplementedException()
, y reenvía las llamadas de método no mutante a la colección real. El hecho de que todas las interfaces de la colección java.util impliquen mutabilidad es una clara señal de que no se esforzaron por un lenguaje de inmutabilidad primero.
La solución que Java presentó para resolver los problemas de concurrencia no era la inmutabilidad, sino el bloqueo generalizado. Cada objeto contiene un mutex que puede usarse para synchronized
bloques o métodos completos. Como resultado, eso no es bueno para el rendimiento, no escala muy bien y es bastante propenso a errores: aún debe lidiar con un estado global mutable.