Na Orientação a Objetos, um Objeto pode ser considerável Imutável mesmo que ele… mude.
Photo by Morgan Harper Nichols on Unsplash
Introdução
O aprendizado de um conceito complexo, tende a ser melhor absorvido se dividirmos o conceito em pequenas partes.
Por exemplo, quando começamos a aprender Inglês, nos é ensinado que, para nos referirmos a algo que ocorreu no passado, devemos utilizar os verbos no passado para fazer afirmações ou utilizamos o verbo modal did ou did not para fazermos perguntas ou negações. Esse é o tempo verbal Simple Past.
Exemplo: I saw this movie (tradução: eu vi esse filme).
Então, quando você começa a estudar mais a língua, descobre que existe muitas outras maneiras de expressar algo que ocorreu no passado. Por exemplo, o uso do tempo verbal Present Perfect.
Exemplo: I have seen this movie (tradução: eu vi esse filme).
Aqui vemos o uso do verbo modal have e o uso do Past Participle do verbo to see.
Ambas as frases dizem o mesmo quando traduzimos para o Português, porém a segunda frase pode ser considerada mais correta do que a primeira — você só descobre isso depois que aprende o Present Perfect. Mas isso não é um blog de Inglês, vamos voltar para a Orientação a Objetos.
Essa introdução é para lhe mostrar que primeiro devemos aprender um conceito na sua forma mais simples; depois aprimoramos.
Conceitos da Imutabilidade
Quando você aprendeu sobre Imutabilidade pode ter pensado que um Objeto é imutável se, depois de criado, nada é alterado dentro dele ou que o Objeto retorna sempre a mesma informação quando um método é chamado.
Bem, não é tão simples assim.
Diferentemente das linguagens funcionais, onde tudo é imutável por padrão, na Orientação a Objetos esse conceito pode ser mais amplo.
Vamos ver alguns conceitos.
Conteúdo Externo
Uma classe que representa um arquivo pode ser imútável de duas maneiras:
No código acima, o método TFile.Stream: IDataStream
sempre irá retornar o mesmo valor lido na primeira execução.
O Objeto é imutável e constante.
Mas, e se alterarmos o método confome abaixo, a classe continuaria sendo imutável?
Sim, com certeza.
Apesar do retorno do método poder ser diferente em cada chamada — o conteúdo do arquivo pode ser alterado por outro processo — o Objeto continuaria sendo imutável pois seu Estado (FFilePath
) não foi alterado.
Ele é imutável, porém não é constante.
O mesmo conceito se aplica para um conteúdo vindo de um Banco de Dados, site na Web, etc.
Conteúdo em Memória
Uma lista de Objetos pode ser considerada imutável se adicionarmos itens após ela ter sido criada?
Vejamos no código:
Copyright (c) James Project
A Classe TDataParams
encapsula uma lista do tipo TInterfaceList
.
A cada inclusão de um novo item, é delegada à essa lista interna, a persistência em memória dos Objetos.
Você acha que, assim, estamos alterando o Estado (FList
) do Objeto?
Não estamos.
O motivo é que não estamos redefinindo FList
. Não estamos recriando uma nova lista.
Uma lista de itens está sendo criada em memória — blocos de memória — mas o endereço inicial de FList
continua intacto.
Além disso, FList
é um Atributo Secundário, então nós até poderíamos redefinir esse atributo sem estar em desacordo com o princípio. Mas, se a instância da lista fosse passada no construtor, então não poderíamos redefinir o Objeto, pois esse seria considerado como um Atributo Primário.
Imutabilidade do Estado
Se mesmo após algumas mudanças internas ou externas ao Objeto, ele continua sendo considerado imutável, como saber se não estamos violando o princípio da Imutabilidade?
Simples: Se o Estado do Objeto, ou seja, seus Atributos Primários, não for alterado/redefinindo, então ele é imutável.
Uma vez que um atributo é instânciado, ele não poderá ter seu endereço de memória alterado. Esses atributos serão inicializados no construtor da classe e jamais poderão ser reinicializados.
Seu Objeto deve ser fiél aos argumentos passados no construtor da Classe, no entanto ele é livre para trabalhar e responder o que quiser em seus métodos.
Conclusão
Imutabilidade, na Orientação a Objetos, não é só sobre as não-mudanças internas ou externas ao Objeto, mas sim sobre não alterar o Estado Primário do Objeto.
Não confunda dados com o Estado do Objeto.
Infelizmente nenhum compilador Object Pascal que eu conheça possui uma sintaxe para que essas regras não sejam quebradas. Java, por exemplo, tem atributos final onde, uma vez inicializados, não podem ter seu endereço de memória substituído.
Sven Barth, um integrante do FPC team, me falou sobre um {$modeswitch
finalfields}
que foi implementado para a interoperabilidade do FPC para a JVM plataforma, porém ainda não disponível.
Então temos que trabalhar apenas com o conceito ou utilizar ferramentas de verificação de código para que essa regra não seja quebrada.
Até logo.