Obteniendo mi cabeza alrededor de la inmutabilidad

13

Soy nuevo en la programación orientada a objetos, y un concepto que me ha llevado un tiempo comprender es la inmutabilidad. Creo que la bombilla se apagó anoche pero quiero verificar:

Cuando me encuentro con afirmaciones de que un objeto inmutable no se puede cambiar, estoy perplejo porque, por ejemplo, puedo hacer lo siguiente:

NSString *myName = @"Bob";
myName = @"Mike";

Allí, acabo de cambiar myName, de tipo inmutable NSString. Mi problema es que la palabra "objeto" puede referirse al objeto físico en la memoria, o la abstracción, "myName". La primera definición se aplica al concepto de inmutabilidad.

En cuanto a la variable, una definición más clara (para mí) de inmutabilidad es que el valor de un objeto inmutable solo puede cambiarse cambiando también su ubicación en la memoria, es decir, su referencia (también conocida como su puntero).

¿Es correcto o todavía estoy perdido en el bosque?

Michael Mangold
fuente
13
Su tipo no es un NSString, es un " puntero a y NSString", que no es inmutable. No sé nada de objetivo C, pero supongo en su ejemplo que @"Mike"es la creación de una nueva instancia de NSStringy asignarlo al puntero , myName. Por lo tanto, no ha cambiado el objeto al que myNameapuntaba, solo a lo que apuntaba.
fwgx
2
@fwgx Ponlo como respuesta y obtendrás mi voto a favor.
Gulshan
Gracias a todos por todas las respuestas, son muy útiles. Ahora entiendo que el objeto inmutable es el valor en memoria, no la variable que lo señala.
Michael Mangold
@Gulshan Hecho, ver más abajo ...
fwgx
Para comprender la inmutabilidad, recomiendo aprender un lenguaje de programación que separe claramente el enlace (es decir, dar nombres a los objetos) con la mutabilidad (es decir, permitir que un nombre se reasigne a un objeto diferente). ML (en cualquier aspecto: SML, Ocaml, F #) es un buen ejemplo.
Gilles 'SO- deja de ser malvado'

Respuestas:

4

Parece que te diriges en la dirección correcta, pero aún no lo entiendo. Esto está mal:

Allí, acabo de cambiar myName, de tipo inmutable NSString. Mi problema es que la palabra "objeto" puede referirse al objeto físico en la memoria, o la abstracción, "myName".

En su fragmento de código, myNameno es de tipo inmutable NSString, es de tipo mutableNSString* (puntero a NSString). Parece que la clave que falta es entender que un puntero es solo otro valor , y tiene una vida completamente separada de lo que señala (o cosas, si lo cambia a mitad de su vida útil).

Tu dices:

... el valor de un objeto inmutable solo puede cambiarse cambiando también su ubicación en la memoria, es decir, su referencia (también conocida como su puntero).

Esto está mal. Un objeto no posee los punteros que apuntan a él, ni la ubicación de la memoria de un objeto está controlada ni afectada por ningún puntero.

Entonces, los dos NSStringobjetos en su ejemplo ( @"Bob"y @"Mike") están completamente separados de la myNamevariable. También están completamente separados el uno del otro. Cuando cambia myNamepara señalar en @"Mike"lugar de señalar @"Bob", no está cambiando los NSStringobjetos.


Para completar, notaré que los recolectores de basura hacen que esto sea más complejo ya que los cambios en los punteros pueden afectar los objetos a los que apuntan (ed). Sin embargo, este es un detalle de implementación que no debería afectar el comportamiento observable del código.

John Bartholomew
fuente
17

Estás perdido en las palabras. La inmutabilidad significa: siempre que no cambie la variable, siempre "contendrá" el mismo valor, sin importar lo que haga con otras variables.

Contraejemplo en C (un poco simplificado, suponiendo una arquitectura que lo permita):

 char *a = "Hello World";
 char *b = a;
 b[0] = 'Y';

Ahora ya no "contiene" (es decir, apunta a) la cadena "Hello World", sino que es "Yello World".

En lenguajes donde las cadenas son inmutables, como Java y (EDITAR: seguro) C #, no puede hacer eso. De ninguna manera. Esto significa que cada parte del programa puede mantener de forma segura una referencia a la cadena y confiar en que su contenido nunca cambie; de lo contrario, tendrían que crear una copia solo para estar seguros.

Pero la variable aún es mutable. Puede dejar que apunte a otro objeto. Es solo que el objeto en sí no cambiará a sus espaldas.

usuario281377
fuente
1
Técnicamente puede modificar el contenido de la cadena en C #, solo tiene que usar el unsafecódigo.
Aaronaught
1
Aaronaught: Gracias por la información, tienes razón; para todos los que necesitan saber cómo: msdn.microsoft.com/en-us/library/ms228599.aspx
user281377
10

Estás confundiendo variables con objetos. Las variables se pueden usar para almacenar referencias a objetos, pero NO son objetos. Los objetos son inmutables, no variables, por lo que puede cambiar la variable de un objeto a otro, pero no puede cambiar los atributos del objeto si es inmutable.

Piense en el objeto como un vecino ruidoso y borracho. Si él es razonable (mutable), puede llamar a su puerta y convertirlo a un estilo de vida donde no haga tanto ruido. Pero si él es inmutable, ¡tu único cambio es esperar que alguien más se mude!

Kilian Foth
fuente
3
He tenido algunos vecinos que me hubiera encantado silenciar.
Dave Nay
No creo que necesite su ejemplo en el segundo párrafo ya que su explicación es lo suficientemente buena. En mi opinión, el ejemplo podría confundir. Sin embargo, +1 para una respuesta sucinta a la pregunta del muchacho.
Paul McCabe
@DaveNay: Pido disculpas por el juego de palabras sigiloso. No fue pensado en absoluto.
Kilian Foth
6

Una variable no es un objeto. Una variable es un nombre, que se refiere a un objeto (o más generalmente a un valor).

Por ejemplo, "el portero" es un nombre que usamos para referirnos al objeto (persona) responsable de defender el objetivo. Pero si sustituyo a esa persona por otra (porque la primera está lesionada o no), la nueva persona ahora se conoce como el "portero".

La declaración de asignación es lo que hace que las variables sean mutables (algunos lenguajes, como Haskell, no lo tienen y, de hecho, usan variables inmutables). Le permite redefinir el significado de un nombre y así reasignar el valor.

Ahora los objetos mismos pueden ser inmutables. Hace unos miles de años, uno podría haber pensado que los diamantes eran inmutables. No importa lo que hiciste con un diamante, no puedes modificarlo. Ya sea que lo llames waggawooga (se traduce libremente como "la piedra brillante más grande de nuestra tribu") o dejaste de llamarlo así (porque encontraste una más grande), el diamante se mantuvo igual. En contraste, el trozo de madera que solías tallar en imágenes divertidas con tu waggawooga no permaneció igual. Resultó mutable. Incluso si tuviera el mismo nombre todo el tiempo.

Tanto las variables como los valores pueden ser inmutables (independientemente). En este caso, son los objetos los que son inmutables. Una vez que construye un NSString, no puede modificarlo. Puedes llamarlo por nombres y pasarlo, pero seguirá igual. En contraste con eso, NSMutableStringse puede cambiar después de la creación, por ejemplo, llamando al setStringmétodo.

back2dos
fuente
Me encanta la comparación de waggawooga!
Michael K
Solo para no confundir el póster original más de lo necesario: aunque su punto de que una variable no es un objeto es bueno, una variable no se define realmente como "un nombre que se refiere a un valor". Posiblemente se nombra una variable y se refiere a una ubicación de almacenamiento que contiene un valor. En muchos lenguajes de programación, las variables no necesitan ser nombradas, y en muchos lenguajes la misma variable puede tener más de un nombre.
Eric Lippert
4

Creo que te sientes perdido, porque estás mezclando dos conceptos: el objeto mismo y el nombre de la variable vinculada a ese objeto.

Los objetos inmutables no se pueden cambiar. Período. Sin embargo, el nombre de la variable (símbolo) vinculado a un objeto inmutable puede modificarse para vincularse a otro objeto inmutable.

En otras palabras, lo que hiciste en estas dos líneas fue:

  1. crear un objeto de cadena inmutable con el valor "Bob"
  2. símbolo de enlace myNamea ese objeto
  3. crear un objeto de cadena inmutable con el valor "Mike"
  4. símbolo de enlace myNamea ese objeto
vartec
fuente
2

Su tipo no es un NSString, es un " puntero a un NSString", que no es inmutable. No sé nada del objetivo C, pero supongo en su ejemplo que @"Mike"está creando una nueva instancia NSStringy asignándola al puntero myName . Por lo que no ha cambiado el objeto que myNameestaba apuntando a, justo lo que estaba señalando.

fwgx
fuente
0

Aquí hay un ejemplo de un objeto mutable: una matriz de charen C:

char str[10];

Puedo cambiar el contenido de strmi corazón (siempre que no sea más de 10 caracteres). Para que sea reconocido como una cadena por las funciones de la biblioteca de cadenas C, debe haber un 0 al final, para que pueda contener cadenas de hasta 9 caracteres de longitud:

strcpy(str, "hello"); // str now contains the string "hello\0"
strcpy(str, "world"); // str now contains the string "world\0"

str[0] = 'W';         // str now contains "World\0"

und so weiter .

Contraste esto con un objeto de cadena en Java:

String foo = "Hello";

La instancia de cadena (el fragmento de memoria que contiene los caracteres 'H', 'e', ​​'l', 'l' y 'o') no se puede modificar; No puedo alterar ninguno de los contenidos de esa cadena. Cuando escribes algo como

foo = foo + " World";

no está agregando "Mundo" al final de la instancia de "Hola"; está creando una nueva instancia , copiando "Hello World" y actualizando foopara referirse a esa nueva instancia de cadena.

foono contiene en sí la instancia de cadena; solo se refiere a esa instancia (similar a un puntero en C u Obj-C), de ahí que los tipos como String se denominen tipos de referencia.

John Bode
fuente