A OOP e a imutabilidade são quase completamente ortogonais entre si. No entanto, a programação imperativa e a imutabilidade não são.
A OOP pode ser resumida por dois recursos principais:
-
Encapsulamento : Eu não irei acessar o conteúdo de objetos diretamente, mas sim me comunicar através de uma interface específica (“métodos”) com este objeto. Essa interface pode ocultar dados internos de mim. Tecnicamente, isso é específico para programação modular em vez de OOP. Acessar dados através de uma interface definida é aproximadamente equivalente a um tipo de dados abstrato.
-
Despacho Dinâmico : Quando eu chamo um método em um objeto, o método executado será resolvido em tempo de execução. (Por exemplo, em OOP baseada em classe, posso chamar um método
size
em uma instânciaIList
, mas a chamada pode ser resolvida para uma implementação em uma classeLinkedList
). O despacho dinâmico é uma maneira de permitir o comportamento polimórfico.
O encapsulamento faz menos sentido sem mutabilidade (não há nenhum estado interno que possa ser corrompido por interferência externa), mas ainda tende a tornar as abstrações mais fáceis mesmo quando tudo é imutável.
Um programa imperativo consiste em declarações que são executadas sequencialmente. Uma declaração tem efeitos colaterais como mudar o estado do programa. Com a imutabilidade, o estado não pode ser alterado (claro, um novo estado pode ser criado). Portanto, a programação imperativa é fundamentalmente incompatível com a imutabilidade.
Acontece agora que a OOP tem sido historicamente sempre conectada com programação imperativa (Simula é baseada em Algol), e todas as principais linguagens OOP possuem raízes imperativas (C ++, Java, C #,… estão todas enraizadas em C). Isto não implica que a OOP em si seja imperativa ou mutável, isto significa apenas que a implementação da OOP por estas linguagens permite a mutabilidade.