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 Ae Bsão iguais se e apenas se existem programas de NO na língua que produzem resultados diferentes quando Aé usado em lugar de B, ou vice-versa. Digamos Ae Bsomos (IEEE 754) flutuadores, e quando substituído na expressão _ + 1.0, o resultado é 1.0para ambos Ae B. Certamente Ae Bsã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 0e B = A. Considere este programa:
A := 1
print(!_)
Substituindo Aimpressões em branco 1e substituindo por Bimpressões 1também. Agora suponha A = ref 0e B = ref 0. Nesse caso, a substituição no programa acima será impressa 1e 0, desde agora, Ae Bapontará 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:
- Depende da capacidade de comparar os valores armazenados nas células de memória para obter igualdade. Igualdade não faz sentido para todos os tipos - por exemplo, geralmente não faz sentido para funções, porque não existe um método geral para determinar se duas funções desconhecidas são iguais (isso está se aventurando no território do Problema de Colocação). Portanto, dadas duas referências às células de memória que armazenam funções, não podemos comparar as funções que elas possuem para a igualdade.
- Depende de ter algum valor que possamos atribuir a uma das duas referências. Portanto, mesmo que a igualdade faça sentido para todos os tipos no idioma, ainda precisamos acessar um valor para cada tipo que queremos comparar. E se a construção de um valor desse tipo tiver efeitos colaterais?
- O valor de referência que usamos para alterar uma das referências deve ser diferente do valor que a célula de memória já possui; portanto, precisamos de dois valores.
- O código para comparar referências de tipos diferentes será exatamente o mesmo, exceto pelos dois valores que usamos.
- Precisamos fazer backup e restaurar o valor da referência que modificamos para evitar alterar o significado do programa.
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 1s estão armazenados em lugares diferentes da memória, pode haver programas que se importam se eu passo um 1ou outro. Eu realmente não quero me preocupar se tenho "o certo 1"; 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.