Eu estava lendo uma proposta para tipos de valor em Java e me deparei com esta frase: "A identidade do objeto serve apenas para suportar a mutabilidade, onde o estado de um objeto pode ser alterado, mas permanece o mesmo objeto intrínseco".
Pelo que entendi (ainda que provisoriamente), a identidade do objeto é a idéia de sua variável agir como um ponteiro ou referência a um objeto localizado em outro lugar na memória (como objetos instanciados no heap em Java ou C #). Então, o que isso teria a ver com a mutabilidade de objetos? Isso implica que, por exemplo, objetos instanciados na pilha em C ++ são imutáveis? Estou tendo problemas para visualizar o link aqui.
java
c++
object-oriented
memory
immutability
Drazen Bjelovuk
fonte
fonte
struct Point {public int x,y;}
, uma declaraçãoPoint pt
deve efetivamente declarar duas variáveis chamadaspt.x
ept.y
. Um parâmetro de método do tipoPoint
deve ser doisint
parâmetros. Sob essas regras, os únicos aspectos que exigiriam qualquer alteração no tempo de execução seriam matrizes e valores de retorno da função. Arrays contendo apenas primitivos ou apenas objetos podem ser manipulados ... #Thread
para mantê-los.Respostas:
Antes de abordar a identidade, vamos definir o que entendemos por igualdade um pouco mais precisamente. Dizemos que duas coisas são iguais se, e somente se, não podemos diferenciá-las (ver: Identidade dos indiscerníveis ). Isso significa que se duas coisas são iguais ou não, depende dos meios que temos para inspecioná-las.
Vamos pensar um pouco mais sobre isso em termos de programação. Vamos deixar nossos preconceitos à porta e supor que estamos trabalhando em uma linguagem desconhecida totalmente nova, onde todas as variáveis e valores são imutáveis. Pela definição de cima, dois valores
A
eB
são iguais se e apenas se existem programas de NO na língua que produzem resultados diferentes quandoA
é usado em lugar deB
, ou vice-versa. DigamosA
eB
somos (IEEE 754) flutuadores, e quando substituído na expressão_ + 1.0
, o resultado é1.0
para ambosA
eB
. CertamenteA
eB
são ambos zero. Eles são iguais? Isso depende - a linguagem fornece alguma função que me permita determinar o sinal do zero? Se não, eles são iguais; se isso acontecer, eles podem não estar.Portanto, dois valores são iguais sempre que fornecem os mesmos resultados para todas as combinações possíveis de operações suportadas. Valores imutáveis, em particular, não produzem resultados diferentes, dependendo de quais operações foram aplicadas anteriormente a eles. Por esse motivo, não nos importamos se duas variáveis apontam para duas cópias do mesmo valor ou se ambas apontam para a mesma cópia.
O que isso tem a ver com mutabilidade? Mutabilidade implica que nossa linguagem tenha alguma noção de uma célula de memória cujo conteúdo possa ser substituído. Digamos que adicionemos suporte a células de memória mutáveis ao nosso idioma:
ref <value>
cria uma nova célula de memória, diferente de todas as outras, inicializada em<value>
.<variable> := <value>
substitui o conteúdo de uma célula de referência.!<variable>
retorna o valor atualmente armazenado em uma célula de referência.Agora vamos pensar sobre o que igualdade significa para células de memória. Suponha
A = ref 0
eB = A
. Considere este programa:Substituindo
A
impressões em branco1
e substituindo porB
impressões1
também. Agora suponhaA = ref 0
eB = ref 0
. Nesse caso, a substituição no programa acima será impressa1
e0
, desde agora,A
eB
apontará para células de memória distintas.Portanto, importa para nós se duas referências apontam para a mesma célula de memória ou células de memória diferentes. Como isso importa, seria útil ter uma maneira eficiente e geral de distinguir duas referências. Nosso método atual de comparar os valores que eles mantêm e, se eles são iguais a uma mutação, é problemático por vários motivos:
Portanto, seria útil para o idioma fornecer uma operação para verificar diretamente se duas referências apontam para a mesma célula de memória mutável. Essa função é inútil para valores imutáveis; na verdade, eu diria que é absolutamente prejudicial. Se existe uma maneira de saber se dois
1
s estão armazenados em lugares diferentes da memória, pode haver programas que se importam se eu passo um1
ou outro. Eu realmente não quero me preocupar se tenho "o certo1
"; a matemática já é difícil o suficiente! Portanto, fica claro que poder verificar a igualdade de memória é útil principalmente para tipos mutáveis.fonte
Imagem que você tem dois objetos, por exemplo, para instâncias da classe
List
. Ambas as listas têm o mesmo conteúdo. Agora você está lendo as listas e calcula e produz algo com base em seu conteúdo. Importa qual lista você usa? Não porque eles têm o mesmo conteúdo.Mas e se uma das listas for alterada? Agora faz importa o que você escolher para a leitura e outputing algo. Portanto, você precisa ser capaz de distinguir entre eles e deseja, mesmo em algumas situações, verificar se duas variáveis apontam para o mesmo objeto (ou lista aqui).
Se, no entanto, você não conseguir alterar o conteúdo de uma lista, não precisará nem ter dois objetos de lista com o mesmo conteúdo, porque não poderá alterá-los. Se você deseja "alterar" o conteúdo, em vez disso, criará um novo objeto de lista com conteúdo diferente - que é como eu disse um novo objeto. Portanto, deste ponto de vista, a identidade não importa. Somente o conteúdo faz e somente o conteúdo deve ser usado para comparar duas listas.
Observe também que o compilador pode apontar para o mesmo objeto de lista, mesmo se você declarar dois objetos, porque ele só precisa armazenar seu conteúdo uma vez, pois não pode ser alterado.
fonte
A identidade do objeto não existe "apenas" para suportar a mutabilidade, mas também tem outros usos [na verdade, uma instância do
Object
tipo é útil apenas como um token de identidade, pois não possui atributos observáveis mutáveis!]. Em vez disso, a identidade geralmente é um - característica indesejada que um objeto mutável adquirirá sempre que existirem várias referências ao objeto, elas não serão todas controladas por um único proprietário e entidades externas ao proprietário poderão - sem o conhecimento do proprietário - fazer ou ver alterações nesse objeto .Suponha que algum campo estático
X
contenha uma referência à instância de elemento único deint[]
e X [0] = 5. O campo estáticoY
também mantém um elemento em uma instância de elemento único deint[]
, e Y [0] = 5. Se o código já chamaIdentityHashCase()
emX
eY
, ou se as análises de códigoX==Y
, ele será capaz de discernir seX
eY
identificar a mesma instânciaint[]
ou instâncias diferentes. Da mesma forma, se o código faz algo parecidoX[0]+=1; Y[0]+=2;
, o comportamento dependerá seX
eY
identificar a mesma instância ou instâncias diferentes. Se, no entanto, o código nunca testarX
eY
explicitamente a igualdade de referência, nem verificar seu código de hash de identidade ou fizer qualquer outra coisa "relacionada a referência", e seX[0]
eY[0]
nunca são modificadosX
eY
serão equivalentes, independentemente de identificarem as mesmas matrizes ou matrizes diferentes.Uma das coisas desagradáveis sobre identidade em Java ou .NET é que a identidade de um objeto depende fundamentalmente do paradeiro de todas as entidades do universo que podem fazer ou ver alterações nesse objeto. Se uma referência a um objeto for exposta livremente a códigos externos, o proprietário do objeto perderá o controle sobre ele e nunca poderá recuperá-lo.
Os tipos de valor, diferentemente dos objetos, nunca podem ser observados ou modificados, exceto pelo objeto ou método em que são declarados. Portanto, um objeto que contém um campo de valor não precisa se preocupar em perder o controle sobre ele, pois é semanticamente impossível que isso aconteça. No .NET (embora não seja Java), é possível transmitir uma variável, campo, elemento da matriz ou outro local de armazenamento como um "parâmetro de referência". Fazer isso temporariamente permitirá que o método observe ou modifique o conteúdo do local de armazenamento passado pela duração de sua execução, mas qualquer "byref" passado (o termo técnico para o que é passado) será destruído antes que o método retorne, garantindo assim que o chamador mantenha controle sobre os dados nele contidos,identidade indesejada .
fonte
Object
tem um atributo mutável muito importante, a exclusão mútua associada!Object
como um token de identidade. Na medida em que eles são vistos como encapsulando um estado mutável em um objeto, não existe um objeto imutável. É irônico que Java às vezes seja visto como uma "linguagem de ensino", uma vez que um objetivo de design mais significativo era simplificar o tempo de execução usando um único tipo de referência; de uma perspectiva semântica, seria melhor distinguir tipos que têm uma identidade daqueles que não têm. O principal benefício dos tipos imutáveis é ... #new String("Hello");
como chave em umIdentityHashMap
, a string se parecerá com qualquer outra string que encapsule esses caracteres a qualquer código que não conheça esse mapa, mas não seria substituível porque seu objeto subjacente teria um token de identidade que era diferente de qualquer outro objeto em todo o universo.Object
. Qualquer definição de imutabilidade em nível de classe que seria satisfeita por, por exemplo,Integer
seria igualmente satisfeita porObject
. Além disso, em geral, quando se diz que um objeto encapsula um estado mutável, é possível copiar significativamente esse estado de uma instância para outra. Eu não acho que haja alguma maneira de copiar o estado de bloqueio de um objeto para outro.