Da minha exposição (reconhecidamente limitada) a linguagens de programação funcionais, como Clojure, parece que o encapsulamento de dados tem um papel menos importante. Geralmente, vários tipos nativos, como mapas ou conjuntos, são a moeda preferida para representar dados, sobre objetos. Além disso, esses dados são geralmente imutáveis.
Por exemplo, aqui está uma das citações mais famosas da fama de Rich Hickey, da Clojure, em um entrevista sobre o assunto :
Fogus: Seguindo essa ideia - algumas pessoas ficam surpresas com o fato de Clojure não se envolver no encapsulamento de ocultação de dados em seus tipos. Por que você decidiu renunciar à ocultação de dados?
Hickey: Vamos deixar claro que Clojure enfatiza fortemente a programação para abstrações. Em algum momento, porém, alguém precisará ter acesso aos dados. E se você tem uma noção de "privado", precisa das noções correspondentes de privilégio e confiança. E isso adiciona uma tonelada de complexidade e pouco valor, cria rigidez em um sistema e muitas vezes força as coisas a viver em lugares que não deveriam. Isso ocorre além das outras perdas que ocorrem quando informações simples são colocadas em classes. Na medida em que os dados são imutáveis, há poucos danos ao fornecer acesso, exceto que alguém pode depender de algo que pode mudar. Bem, tudo bem, as pessoas fazem isso o tempo todo na vida real e, quando as coisas mudam, elas se adaptam. E se eles são racionais, eles sabem quando tomam uma decisão com base em algo que pode mudar que eles possam, no futuro, precisar se adaptar. Portanto, é uma decisão de gerenciamento de riscos, que eu acho que os programadores devem ser livres para tomar. Se as pessoas não têm a sensibilidade de desejar programar para abstrações e desconfiar de se casar com os detalhes da implementação, nunca serão bons programadores.
Vindo do mundo OO, isso parece complicar alguns dos princípios consagrados que aprendi ao longo dos anos. Entre eles, a ocultação de informações, a lei de Demeter e o princípio de acesso uniforme, para citar alguns. O encadeamento comum é que o encapsulamento nos permite definir uma API para que outras pessoas saibam o que devem ou não tocar. Em essência, a criação de um contrato que permita ao mantenedor de algum código fazer livremente alterações e refatorações sem se preocupar com a maneira como ele pode introduzir bugs no código do consumidor (princípio Aberto / Fechado). Ele também fornece uma interface limpa e com curadoria para outros programadores saberem quais ferramentas eles podem usar para acessar ou desenvolver esses dados.
Quando os dados podem ser acessados diretamente, o contrato da API é quebrado e todos esses benefícios de encapsulamento parecem desaparecer. Além disso, dados estritamente imutáveis parecem tornar a passagem por estruturas específicas de domínio (objetos, estruturas, registros) muito menos úteis no sentido de representar um estado e o conjunto de ações que podem ser executadas nesse estado.
Como as bases de código funcionais abordam esses problemas que parecem surgir quando o tamanho de uma base de código aumenta enorme, de modo que as APIs precisam ser definidas e muitos desenvolvedores estão envolvidos no trabalho com partes específicas do sistema? Existem exemplos dessa situação disponíveis que demonstram como isso é tratado nesse tipo de base de código?
Also, strictly immutable data seems to make passing around domain-specific structures (objects, structs, records) much less useful in the sense of representing a state and the set of actions that can be performed on that state.
Na verdade não. A única coisa que muda é que as alterações acabam em um novo objeto. Essa é uma grande vitória quando se trata de raciocinar sobre o código; passar objetos mutáveis significa ter que rastrear quem pode modificá-los, um problema que aumenta com o tamanho do código.