Estaba leyendo una propuesta para los tipos de valor en Java , y me encontré con esta oración: "La identidad del objeto sirve solo para soportar la mutabilidad, donde el estado de un objeto puede ser mutado pero sigue siendo el mismo objeto intrínseco".
Por lo que entiendo (aunque provisionalmente), la identidad del objeto es la idea de que su variable actúe como un puntero o referencia a un objeto ubicado en otra parte de la memoria (como los objetos instanciados en el montón en Java o C #). Entonces, ¿qué tendría esto que ver con la mutabilidad del objeto? ¿Esto implica que, por ejemplo, los objetos instanciados en la pila en C ++ son inmutables? Tengo problemas para ver el enlace aquí.
java
c++
object-oriented
memory
immutability
Drazen Bjelovuk
fuente
fuente
struct Point {public int x,y;}
, una declaraciónPoint pt
debería declarar efectivamente dos variables llamadaspt.x
ypt.y
. Un parámetro de tipo de métodoPoint
debe ser dosint
parámetros. Bajo tales reglas, los únicos aspectos que requerirían cualquier cambio en el tiempo de ejecución serían matrices y valores de retorno de funciones. Las matrices que contienen solo primitivas o solo objetos podrían manejarse ...Thread
para mantenerlos.Respuestas:
Antes de abordar la identidad, definamos lo que entendemos por igualdad un poco más precisamente. Decimos que dos cosas son iguales si y solo si no podemos distinguirlas (ver: Identidad de indiscernibles ). Eso significa que si dos cosas son iguales o no depende de los medios que tengamos para inspeccionarlas.
Pensemos en eso un poco más en términos de programación. Dejemos nuestras ideas preconcebidas en la puerta y supongamos que estamos trabajando en un nuevo lenguaje desconocido donde todas las variables y valores son inmutables. Según la definición anterior, dos valores
A
yB
son iguales si y solo si NO hay programas en el lenguaje que produzcan resultados diferentes cuandoA
se usan en lugar deB
o viceversa. DigamosA
yB
son flotantes (IEEE 754), y cuando se sustituyen en la expresión_ + 1.0
, el resultado es1.0
para ambosA
yB
. SeguramenteA
yB
ambos son cero. ¿Son iguales? Eso depende: ¿el lenguaje proporciona alguna función que me permita determinar el signo del cero?? Si no es así, son iguales; si lo hace, pueden no serlo.Por lo tanto, dos valores son iguales cada vez que dan los mismos resultados para todas las combinaciones posibles de operaciones que admiten. Los valores inmutables en particular no producen resultados diferentes dependiendo de las operaciones que se les aplicaron previamente. Por esa razón, no nos importa si dos variables apuntan a dos copias del mismo valor o si ambas apuntan a la misma copia.
¿Qué tiene esto que ver con la mutabilidad? La mutabilidad implica que nuestro lenguaje tiene una noción de una celda de memoria cuyos contenidos pueden sobrescribirse. Digamos que agregamos soporte para celdas de memoria mutables a nuestro idioma:
ref <value>
crea una nueva celda de memoria, distinta de todas las demás, inicializada en<value>
.<variable> := <value>
sobrescribe el contenido de una celda de referencia.!<variable>
devuelve el valor actualmente almacenado en una celda de referencia.Ahora pensemos en lo que significa la igualdad para las celdas de memoria. Supongamos
A = ref 0
yB = A
. Considere este programa:Sustituyendo las
A
impresiones en blanco1
y sustituyendo también por lasB
impresiones1
. Ahora supongamosA = ref 0
yB = ref 0
. En este caso, sustituyendo en el programa imprime anteriores1
y0
, desde ahoraA
yB
punto a distintas celdas de memoria.Por lo tanto, nos importa si dos referencias apuntan a la misma celda de memoria o diferentes celdas de memoria. Como eso es importante, sería útil tener una forma eficiente y general de distinguir dos referencias. Nuestro método actual de comparar los valores que tienen, y si son iguales, mutar uno de ellos es problemático por varias razones:
Por lo tanto, sería útil que el lenguaje proporcione una operación para verificar directamente si dos referencias apuntan a la misma celda de memoria mutable. Tal función no tiene sentido para valores inmutables; de hecho, diría que es francamente dañino. Si existía una forma de saber si dos
1
s están almacenados en diferentes lugares en la memoria, entonces puede haber programas que se preocupen si paso uno1
u otro. Realmente no quiero preocuparme si tengo "el derecho1
"; ¡las matemáticas ya son bastante difíciles! Por lo tanto, está claro que poder verificar la igualdad de memoria es principalmente útil para los tipos mutables.fuente
Imagen que tiene dos objetos, por ejemplo, a instancias de la clase
List
. Ambas listas tienen el mismo contenido. Ahora está leyendo las listas y calcula y genera algo basado en su contenido. ¿Importa qué lista usas? No lo hace porque tienen el mismo contenido.Pero, ¿y si se cambia una de las listas? Ahora sí importa cuál elijas para leer y generar algo. Por lo tanto, debe poder distinguir entre ellos y desea, incluso en algunas situaciones, poder verificar si dos variables apuntan al mismo objeto (o la lista aquí).
Sin embargo, si no puede cambiar el contenido de una lista, entonces ni siquiera necesita tener dos objetos de lista con el mismo contenido porque no puede cambiarlos de todos modos. Si desea "cambiar" el contenido, en su lugar creará un nuevo objeto de lista con contenido diferente, que es como dije un nuevo objeto. Entonces, desde este punto de vista, la identidad no importa. Solo el contenido lo hace y solo el contenido debe usarse para comparar dos listas.
También tenga en cuenta que el compilador podría apuntar al mismo objeto de lista incluso si declara dos objetos porque solo necesita almacenar su contenido una vez, ya que no puede cambiar.
fuente
La identidad del objeto no existe "sólo" a la mutabilidad de apoyo, pero tiene otros usos, así [de hecho, una instancia de
Object
tipo es útil sólo como un testigo de identidad, ya que cuenta con atributos no observable-mutables en absoluto!] En cambio, la identidad es una frecuencia - característica no deseada de que un objeto mutable adquirirá cada vez que existan múltiples referencias al objeto, no todos están controlados por un solo propietario y las entidades ajenas al propietario pueden, sin el conocimiento del propietario, realizar o ver cambios en ese objeto .Suponga que algún campo estático
X
contiene una referencia a la instancia de elemento único deint[]
, y X [0] = 5. El campo estáticoY
también contiene un elemento para una instancia de un solo elemento deint[]
, y Y [0] = 5. Si el código cada vez llamaIdentityHashCase()
enX
eY
, o si los análisis de códigoX==Y
, será capaz de discernir siX
yY
identificar la misma instancia delint[]
o diferentes instancias. Del mismo modo, si el código hace algo asíX[0]+=1; Y[0]+=2;
, el comportamiento dependerá de siX
y deY
identificar a la misma instancia o instancias diferentes. Sin embargo, si el código nunca pruebaX
yY
explícitamente la igualdad de referencia, ni verifica su código hash de identidad, o hace algo más "relacionado con la referencia", y siX[0]
yY[0]
nunca se modifican, entonces,X
yY
serán equivalentes independientemente de si identifican las mismas matrices o matrices diferentes.Una de las cosas desagradables sobre la identidad en Java o .NET es que la identidad de un objeto depende fundamentalmente del paradero de cada entidad en el universo que pueda hacer o ver cambios en ese objeto. Si una referencia a un objeto se expone libremente a un código externo, el propietario del objeto perderá el control sobre él y nunca podrá recuperarlo.
Los tipos de valor, a diferencia de los objetos, nunca se pueden observar o modificar, excepto por el objeto o método en el que se declaran. Por lo tanto, un objeto que contiene un campo de tipo de valor no tiene que preocuparse por perder el control sobre él, ya que es semánticamente imposible que eso suceda. En .NET (aunque no Java) es posible pasar una variable, campo, elemento de matriz u otra ubicación de almacenamiento como un "parámetro de referencia". Si lo hace, permitirá temporalmente que el método observe o modifique el contenido de la ubicación de almacenamiento aprobada mientras dure su ejecución, pero se garantiza que cualquier "byref" aprobado (el término técnico para lo que se pasa) se destruirá antes de que el método regrese, asegurando así que la persona que llama mantiene el control sobre los datos que contiene,identidad no deseada
fuente
Object
tiene un atributo mutable muy importante, la exclusión mutua asociada.Object
como token de identidad. En la medida en que se vean como estado mutable encapsulante en un objeto, no existe un objeto inmutable. Es irónico que Java a veces se vea como un "lenguaje de enseñanza", dado que un objetivo de diseño más significativo era simplificar el tiempo de ejecución utilizando un solo tipo de referencia; desde una perspectiva semántica, hubiera sido mejor distinguir los tipos que tienen una identidad de los que no. El beneficio principal de los tipos inmutables es ...new String("Hello");
como una clave en unIdentityHashMap
, la cadena se vería como cualquier otra cadena que encapsula esos caracteres a cualquier código que no conociera ese mapa, pero no sería sustituible porque su objeto subyacente tendría un token de identidad que era diferente de cualquier otro objeto en todo el universo.Object
. Cualquier definición de inmutabilidad a nivel de clase que se satisfaría, por ejemploInteger
, sería igualmente satisfecha porObject
. Además, en general, cuando se dice que un objeto encapsula el estado mutable, es posible copiar significativamente ese estado de una instancia a otra. No creo que haya forma de copiar el estado de bloqueo de un objeto a otro.