Estou tentando entender os objetos mutáveis e imutáveis. O uso de objetos mutáveis causa muita má impressão (por exemplo, retornando uma matriz de seqüências de caracteres de um método), mas estou tendo problemas para entender quais são os impactos negativos disso. Quais são as práticas recomendadas para o uso de objetos mutáveis? Você deve evitá-los sempre que possível?
oop
immutability
mutable
Alex Angas
fonte
fonte
string
é imutável, pelo menos no .NET, e acho que em muitas outras linguagens modernas também.Respostas:
Bem, existem alguns aspectos nisso.
Objetos mutáveis sem identidade de referência podem causar erros em momentos estranhos. Por exemplo, considere um
Person
bean com umequals
método baseado em valor :A
Person
instância é "perdida" no mapa quando usada como chave, porque suahashCode
igualdade e foram baseadas em valores mutáveis. Esses valores foram alterados fora do mapa e todo o hash se tornou obsoleto. Os teóricos gostam de falar sobre esse ponto, mas, na prática, não achei que fosse um problema demais.Outro aspecto é a "razoabilidade" lógica do seu código. Este é um termo difícil de definir, abrangendo tudo, desde a legibilidade ao fluxo. Genericamente, você deve poder analisar um pedaço de código e entender facilmente o que ele faz. Mais importante do que isso, você deve conseguir se convencer de que faz o que faz corretamente . Quando os objetos podem mudar independentemente entre diferentes "domínios" de código, às vezes fica difícil acompanhar o que é onde e por quê (" ação assustadora à distância "). Esse é um conceito mais difícil de exemplificar, mas geralmente é enfrentado em arquiteturas maiores e mais complexas.
Finalmente, objetos mutáveis são matadores em situações simultâneas. Sempre que você acessar um objeto mutável a partir de threads separados, precisará lidar com o bloqueio. Isso reduz a taxa de transferência e torna seu código muito mais difícil de manter. Um sistema suficientemente complicado explode esse problema tão fora de proporção que se torna quase impossível de manter (mesmo para especialistas em concorrência).
Objetos imutáveis (e mais particularmente coleções imutáveis) evitam todos esses problemas. Depois de entender como eles funcionam, seu código se transformará em algo mais fácil de ler, mais fácil de manter e com menor probabilidade de falhar de maneiras estranhas e imprevisíveis. Objetos imutáveis são ainda mais fáceis de testar, devido não apenas à sua facilidade de zombaria, mas também aos padrões de código que eles tendem a impor. Em suma, são boas práticas ao redor!
Com isso dito, dificilmente sou fanático por esse assunto. Alguns problemas simplesmente não são bons quando tudo é imutável. Mas eu acho que você deve tentar empurrar o máximo de seu código nessa direção possível, assumindo, é claro, que você esteja usando uma linguagem que faça disso uma opinião sustentável (C / C ++ torna isso muito difícil, assim como Java) . Em resumo: as vantagens dependem um pouco do seu problema, mas eu preferiria a imutabilidade.
fonte
Objetos imutáveis vs. coleções imutáveis
Um dos pontos mais delicados do debate sobre objetos mutáveis e imutáveis é a possibilidade de estender o conceito de imutabilidade às coleções. Um objeto imutável é um objeto que geralmente representa uma única estrutura lógica de dados (por exemplo, uma sequência imutável). Quando você tem uma referência a um objeto imutável, o conteúdo do objeto não muda.
Uma coleção imutável é uma coleção que nunca muda.
Quando executo uma operação em uma coleção mutável, altero a coleção no local, e todas as entidades que têm referências à coleção verão a alteração.
Quando executo uma operação em uma coleção imutável, uma referência é retornada para uma nova coleção que reflete a alteração. Todas as entidades que têm referências a versões anteriores da coleção não verão a alteração.
Implementações inteligentes não precisam necessariamente copiar (clonar) toda a coleção para fornecer essa imutabilidade. O exemplo mais simples é a pilha implementada como uma lista vinculada única e as operações push / pop. Você pode reutilizar todos os nós da coleção anterior na nova coleção, adicionando apenas um nó para o envio e clonando nenhum nó para o pop. A operação push_tail em uma lista isolada, por outro lado, não é tão simples ou eficiente.
Variáveis / referências imutáveis vs. mutáveis
Algumas linguagens funcionais adotam o conceito de imutabilidade para fazer referência a objetos, permitindo apenas uma única atribuição de referência.
Facilidade de Desenvolvimento vs. Desempenho
Quase sempre o motivo para usar um objeto imutável é promover a programação livre de efeitos colaterais e o raciocínio simples sobre o código (especialmente em um ambiente paralelo / altamente concorrente). Você não precisa se preocupar com os dados subjacentes sendo alterados por outra entidade se o objeto for imutável.
A principal desvantagem é o desempenho. Aqui está uma descrição de um teste simples que fiz em Java, comparando alguns objetos imutáveis versus mutáveis em um problema de brinquedo.
Os problemas de desempenho são discutíveis em muitos aplicativos, mas não em todos, e é por isso que muitos pacotes numéricos grandes, como a classe Numpy Array no Python, permitem atualizações no local de matrizes grandes. Isso seria importante para áreas de aplicação que fazem uso de grandes operações matriciais e vetoriais. Esses grandes problemas paralelos a dados e intensivos em computação alcançam uma grande velocidade ao operar no local.
fonte
Verifique esta postagem do blog: http://www.yegor256.com/2014/06/09/objects-should-be-immutable.html . Explica por que objetos imutáveis são melhores que mutáveis. Em resumo:
fonte
Objetos imutáveis são um conceito muito poderoso. Eles tiram muito do fardo de tentar manter objetos / variáveis consistentes para todos os clientes.
Você pode usá-los para objetos de baixo nível, não polimórficos - como uma classe CPoint - que são usados principalmente com semântica de valores.
Ou você pode usá-los para interfaces polimórficas de alto nível - como uma função IF representando uma função matemática - que é usada exclusivamente com semântica de objetos.
Maior vantagem: imutabilidade + semântica de objetos + ponteiros inteligentes tornam a propriedade do objeto um problema, todos os clientes do objeto têm sua própria cópia privada por padrão. Implicitamente, isso também significa comportamento determinístico na presença de simultaneidade.
Desvantagem: quando usado com objetos que contêm muitos dados, o consumo de memória pode se tornar um problema. Uma solução para isso pode ser manter as operações em um objeto simbólico e fazer uma avaliação lenta. No entanto, isso pode levar a cadeias de cálculos simbólicos, que podem influenciar negativamente o desempenho se a interface não for projetada para acomodar operações simbólicas. Definitivamente, algo a ser evitado nesse caso está retornando grandes pedaços de memória de um método. Em combinação com operações simbólicas encadeadas, isso pode levar a um enorme consumo de memória e degradação do desempenho.
Objetos tão imutáveis são definitivamente minha principal maneira de pensar sobre design orientado a objetos, mas eles não são um dogma. Eles resolvem muitos problemas para clientes de objetos, mas também criam muitos, especialmente para os implementadores.
fonte
Você deve especificar o idioma que está falando. Para linguagens de baixo nível, como C ou C ++, prefiro usar objetos mutáveis para economizar espaço e reduzir a perda de memória. Em linguagens de nível superior, objetos imutáveis facilitam a discussão sobre o comportamento do código (especialmente o código multiencadeado) porque não há "ação assustadora à distância".
fonte
Um objeto mutável é simplesmente um objeto que pode ser modificado após ser criado / instanciado, versus um objeto imutável que não pode ser modificado (consulte a página da Wikipedia sobre o assunto). Um exemplo disso em uma linguagem de programação são as listas e as tuplas do Pythons. As listas podem ser modificadas (por exemplo, novos itens podem ser adicionados após a criação), enquanto as tuplas não podem.
Eu realmente não acho que exista uma resposta clara sobre qual é melhor para todas as situações. Ambos têm seus lugares.
fonte
Se um tipo de classe é mutável, uma variável desse tipo de classe pode ter vários significados diferentes. Por exemplo, suponha que um objeto
foo
tenha um campoint[] arr
e mantenha uma referência a umaint[3]
retenção dos números {5, 7, 9}. Embora o tipo do campo seja conhecido, há pelo menos quatro coisas diferentes que ele pode representar:Uma referência potencialmente compartilhada, cujos detentores se importam apenas em encapsular os valores 5, 7 e 9. Se
foo
desejararr
encapsular valores diferentes, deve substituí-lo por uma matriz diferente que contenha os valores desejados. Se alguém quiser fazer uma cópia defoo
, poderá dar à cópia uma referênciaarr
ou uma nova matriz contendo os valores {1,2,3}, o que for mais conveniente.A única referência, em qualquer lugar do universo, a uma matriz que encapsula os valores 5, 7 e 9. conjunto de três locais de armazenamento que atualmente mantêm os valores 5, 7 e 9; se
foo
desejar encapsular os valores 5, 8 e 9, ele pode alterar o segundo item nessa matriz ou criar uma nova matriz contendo os valores 5, 8 e 9 e abandonar a antiga. Observe que, se alguém quiser fazer uma cópia defoo
, deve-se na cópia substituirarr
por uma referência a uma nova matrizfoo.arr
para permanecer como a única referência a essa matriz em qualquer lugar do universo.Uma referência a uma matriz que pertence a algum outro objeto que a tenha exposto
foo
por algum motivo (por exemplo, talvez ele queirafoo
armazenar alguns dados lá). Nesse cenário,arr
não encapsula o conteúdo da matriz, mas sua identidade . Como a substituiçãoarr
por uma referência a uma nova matriz mudaria totalmente seu significado, uma cópia defoo
deveria conter uma referência à mesma matriz.Uma referência a uma matriz da qual
foo
é o único proprietário, mas à qual as referências são mantidas por outro objeto por algum motivo (por exemplo, ele deseja ter o outro objeto para armazenar dados lá - o outro lado do caso anterior). Nesse cenário,arr
encapsula a identidade da matriz e seu conteúdo. Substituirarr
por uma referência a uma nova matriz mudaria totalmente seu significado, mas aarr
referência de um clonefoo.arr
violaria a suposição de quefoo
é o único proprietário. Portanto, não há como copiarfoo
.Em teoria,
int[]
deve ser um tipo bem simples e bem definido, mas tem quatro significados muito diferentes. Por outro lado, uma referência a um objeto imutável (por exemploString
) geralmente tem apenas um significado. Grande parte do "poder" de objetos imutáveis decorre desse fato.fonte
Instâncias mutáveis são passadas por referência.
Instâncias imutáveis são passadas por valor.
Exemplo abstrato. Suponha que exista um arquivo chamado txtfile no meu disco rígido. Agora, quando você me pede o txtfile , posso devolvê-lo de dois modos:
No primeiro modo, txtfile retornado é um arquivo mutável, porque quando você faz alterações no arquivo de atalho, também faz alterações no arquivo original. A vantagem desse modo é que cada atalho retornado requer menos memória (na RAM ou no HDD) e a desvantagem é que todos (não apenas eu, proprietário) têm permissões para modificar o conteúdo do arquivo.
No segundo modo, txtfile retornado é um arquivo imutável, porque todas as alterações no arquivo recebido não se referem ao arquivo original. A vantagem desse modo é que apenas eu (proprietário) podemos modificar o arquivo original e a desvantagem é que cada cópia retornada requer memória (na RAM ou no HDD).
fonte
Se você retornar referências de uma matriz ou sequência, o mundo exterior poderá modificar o conteúdo desse objeto e, portanto, torná-lo como objeto mutável (modificável).
fonte
Meios imutáveis não podem ser alterados e mutáveis significa que você pode mudar.
Os objetos são diferentes das primitivas em Java. As primitivas são construídas em tipos (booleano, int, etc) e objetos (classes) são tipos criados pelo usuário.
Primitivos e objetos podem ser mutáveis ou imutáveis quando definidos como variáveis de membro na implementação de uma classe.
Muitas pessoas pensam que primitivas e variáveis de objeto com um modificador final na frente delas são imutáveis, no entanto, isso não é exatamente verdade. Portanto, final quase não significa imutável para variáveis. Veja o exemplo aqui
http://www.siteconsortium.com/h/D0000F.php .
fonte
Immutable object
- é um estado do objeto que não pode ser alterado após a criação. O objeto é imutável quando todos os campos são imutáveisDiscussão segura
A principal vantagem do objeto Imutável é que ele é um ambiente natural para simultâneo. O maior problema na simultaneidade é o
shared resource
que pode ser alterado em qualquer segmento. Porém, se um objeto é imutável, éread-only
essa a operação segura do thread. Qualquer modificação de um objeto imutável original retorna uma cópiaefeitos colaterais grátis
Como desenvolvedor, você tem certeza absoluta de que o estado do objeto imutável não pode ser alterado de nenhum lugar (de propósito ou não)
otimização de compilação
Melhorar o desempenho
Desvantagem:
A cópia do objeto é uma operação mais pesada do que a alteração de um objeto mutável, é por isso que ele tem alguma pegada de desempenho
Para criar um
immutable
objeto, você deve usar:Nível de idioma. Cada idioma contém ferramentas para ajudá-lo. Por exemplo, Java possui
final
eprimitives
, Swift possuilet
estruct
[Sobre] . Idioma define um tipo de variável. Por exemplo, Java possuiprimitive
ereference
digite, Swift possuivalue
ereference
digite [Sobre] . Para objetos imutáveis, é mais conveniente o tipoprimitives
e ovalue
tipo que faz uma cópia por padrão. Quanto aoreference
tipo, é mais difícil (porque você pode alterar o estado do objeto), mas é possível. Por exemplo, você pode usarclone
padrão no nível do desenvolvedorNível de desenvolvedor. Como desenvolvedor, você não deve fornecer uma interface para alterar o estado
fonte