Obtendo minha cabeça em torno da imutabilidade

13

Eu sou novo na programação orientada a objetos, e um conceito que me levou um tempo para entender é a imutabilidade. Acho que a lâmpada se apagou ontem à noite, mas quero verificar:

Quando me deparo com afirmações de que um objeto imutável não pode ser alterado, fico perplexo porque posso, por exemplo, fazer o seguinte:

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

Lá, eu mudei myName, do tipo imutável NSString. Meu problema é que a palavra "objeto" pode se referir ao objeto físico na memória ou à abstração "meu nome". A definição anterior se aplica ao conceito de imutabilidade.

Quanto à variável, uma definição mais clara (para mim) de imutabilidade é que o valor de um objeto imutável só pode ser alterado mudando também sua localização na memória, ou seja, sua referência (também conhecida como ponteiro).

Isso está correto ou ainda estou perdido na floresta?

Michael Mangold
fonte
13
Seu tipo não é um NSString, é um " ponteiro para e NSString", o que não é imutável. Eu não sei nada de C objetivo, mas eu estou supondo que no seu exemplo que @"Mike"é a criação de uma nova instância NSStringe atribuindo-o para o ponteiro , myName. Portanto, você não alterou o objeto que myNameestava apontando, apenas para o que estava apontando.
Fwgx
2
@fwgx Coloque-o como resposta e você receberá meu voto positivo.
Gulshan
Obrigado a todos por todas as respostas, elas são muito úteis. Agora entendo que o objeto imutável é o valor na memória, não a variável que aponta para ele.
Michael Mangold
@Gulshan Feito, veja abaixo ....
fwgx
Para entender a imutabilidade, recomendo aprender uma linguagem de programação que claramente separe a ligação (por exemplo, dar nomes aos objetos) à mutabilidade (por exemplo, permitindo que um nome seja reatribuído para um objeto diferente). ML (de qualquer forma: SML, Ocaml, F #) é um bom exemplo.
Gilles 'SO- stop be evil'

Respostas:

4

Parece que você está indo na direção certa, mas ainda não a conseguiu. Isto está errado:

Lá, eu mudei myName, do tipo imutável NSString. Meu problema é que a palavra "objeto" pode se referir ao objeto físico na memória ou à abstração "meu nome".

No seu snippet de código, myNamenão é do tipo imutável NSString, é do tipo mutávelNSString* (ponteiro para NSString). Parece que a principal coisa que você está perdendo é entender que um ponteiro é apenas outro valor e tem uma vida completamente separada da que ele aponta (ou coisas, se você o alterar parcialmente durante sua vida útil).

Você diz:

... o valor de um objeto imutável só pode ser alterado alterando também sua localização na memória, ou seja, sua referência (também conhecida como ponteiro).

Isto está errado. Um objeto não possui os ponteiros que apontam para ele, nem a localização da memória de um objeto é controlada ou afetada por outros ponteiros.

Portanto, os dois NSStringobjetos no seu exemplo ( @"Bob"e @"Mike") são completamente separados da myNamevariável. Eles também são completamente separados um do outro. Quando você muda myNamepara apontar para em @"Mike"vez de apontar para @"Bob", você não está alterando os NSStringobjetos.


Para completar, observarei que os coletores de lixo tornam isso mais complexo, pois as alterações nos ponteiros podem afetar os objetos para os quais eles apontam (ed). No entanto, este é um detalhe de implementação que não deve afetar o comportamento observável do código.

John Bartholomew
fonte
17

Você está perdido em palavras. Imutabilidade significa: Contanto que você não altere a variável, ela sempre "conterá" o mesmo valor, não importa o que você faça com outras variáveis.

Contra-exemplo em C (um pouco simplificado, assumindo uma arquitetura que permite isso):

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

Agora já não "contém" (ou seja, aponta para) a string "Hello World", mas é "Yello World".

Nas linguagens em que as strings são imutáveis, como Java e (EDIT: safe) C #, você não pode fazer isso. De jeito nenhum. Isso significa que todas as partes do programa podem manter com segurança uma referência à string e confiar que seu conteúdo nunca muda; caso contrário, eles teriam que criar uma cópia apenas para estar do lado seguro.

Mas a variável ainda é mutável. Você pode deixá-lo apontar para outro objeto. Só que o objeto em si não muda nas suas costas.

user281377
fonte
1
Tecnicamente, você pode modificar o conteúdo da string em C #, basta usar o unsafecódigo.
Aaronaught
1
Aaronaught: Obrigado pela informação, você está certo; para todos que precisam saber como: msdn.microsoft.com/en-us/library/ms228599.aspx
user281377
10

Você está confundindo variáveis ​​com objetos. Variáveis ​​podem ser usadas para armazenar referências a objetos, mas NÃO são objetos. São objetos imutáveis, não variáveis; portanto, você pode alterar a variável de um objeto para outro, mas não pode alterar os atributos do objeto, se for imutável.

Pense no objeto como um vizinho barulhento e barulhento. Se ele for razoável (mutável), você poderá bater na porta dele e convertê-lo em um estilo de vida em que ele não faça tanto barulho. Mas se ele é imutável, sua única mudança é esperar que mais alguém se mude!

Kilian Foth
fonte
3
Eu tive alguns vizinhos que eu adoraria silenciar.
Dave Nay
Eu não acho que você precise do seu exemplo no segundo parágrafo, pois sua explicação é boa o suficiente. IMO o exemplo poderia apenas confundir. No entanto, +1 para uma resposta sucinta à pergunta do sujeito.
Paul McCabe
@DaveNay: Peço desculpas pelo trocadilho furtivo. Não foi intencional.
Kilian Foth
6

Uma variável não é um objeto. Uma variável é um nome, que se refere a um objeto (ou mais geralmente a um valor).

Por exemplo, "o goleiro" é um nome que usamos para nos referir ao objeto (pessoa) responsável pela defesa do gol. Mas se eu substituir essa pessoa por outra (porque a primeira está machucada ou não), a nova pessoa agora é chamada de "goleiro".

A declaração de atribuição é o que torna variáveis ​​mutáveis ​​(alguns idiomas, como Haskell, não o possuem e, de fato, usam variáveis ​​imutáveis). Permite redefinir o significado de um nome e, assim, reatribuir o valor.

Agora, os próprios objetos podem ser imutáveis. Alguns milhares de anos atrás, poderia-se pensar nos diamantes como imutáveis. Não importa o que você fez com um diamante, você não pode modificá-lo. Quer você chamasse waggawooga (traduz-se vagamente na "maior pedra brilhante da nossa tribo") ou deixou de chamá-lo dessa maneira (porque você encontrou uma maior), o diamante permaneceu o mesmo. Por outro lado, o pedaço de madeira que você costumava esculpir em fotos engraçadas com a sua waggawooga não permaneceu o mesmo. Isso se mostrou mutável. Mesmo que tivesse o mesmo nome o tempo todo.

Tanto as variáveis ​​quanto os valores podem ser imutáveis ​​(independentemente). Nesse caso, são os objetos imutáveis. Depois de construir um NSString, você não pode modificá-lo. Você pode chamá-lo de nomes e passá-lo, mas permanecerá o mesmo. Em contraste com isso, NSMutableStringpode ser alterado após a criação, por exemplo, chamando o setStringmétodo

back2dos
fonte
Adoro a comparação waggawooga!
Michael K
Apenas para não confundir o pôster original mais do que o necessário: embora seu argumento de que uma variável não seja um objeto seja bom, uma variável não é realmente definida como "um nome que se refere a um valor". Uma variável é possivelmente nomeada e refere-se a um local de armazenamento que contém um valor. Em muitas linguagens de programação, as variáveis ​​não precisam ser nomeadas e, em muitas linguagens, a mesma variável pode ter mais de um nome.
precisa
4

Eu acho que você se sente perdido, porque está misturando dois conceitos: objeto em si e nome da variável vinculado a esse objeto.

Objetos imutáveis ​​não podem ser alterados. Período. No entanto, o nome da variável (símbolo) vinculado a um objeto imutável pode ser modificado para ser vinculado a outro objeto imutável.

Em outras palavras, o que você fez nessas duas linhas foi:

  1. criar objeto de string imutável com o valor "Bob"
  2. símbolo de ligação myNamea esse objeto
  3. criar objeto de string imutável com o valor "Mike"
  4. símbolo de ligação myNamea esse objeto
vartec
fonte
2

Seu tipo não é um NSString, é um " ponteiro para um NSString", o que não é imutável. Não sei nada sobre o objetivo C, mas, no seu exemplo, acho que @"Mike"é criar uma nova instância NSStringe atribuí-la ao ponteiro myName . Portanto, você não alterou o objeto que myNameestava apontando , apenas para o que estava apontando.

fwgx
fonte
0

Aqui está um exemplo de um objeto mutável: uma matriz charem C:

char str[10];

Posso alterar o conteúdo do conteúdostr para o meu coração (desde que não tenha mais que 10 caracteres). Para que seja reconhecido como uma string pelas funções da biblioteca de strings C, deve haver um 0 à direita, para que ele possa conter strings com até 9 caracteres de comprimento:

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 weiter .

Compare isso com um objeto de string em Java:

String foo = "Hello";

A instância da string (o pedaço de memória que contém os caracteres 'H', 'e', ​​'l', 'l' e 'o') não pode ser modificado; Não posso alterar nenhum conteúdo dessa sequência. Quando você escreve algo como

foo = foo + " World";

você não está anexando "Mundo" ao final da instância "Olá"; você está criando uma nova instância , copiando "Hello World" para ela e atualizando foopara se referir a essa nova instância de string.

fooele próprio não contém a instância da string; refere-se apenas a essa instância (semelhante a um ponteiro em C ou Obj-C); portanto, por que tipos como String são chamados de tipos de referência.

John Bode
fonte