Nas linguagens de programação, os fechamentos são um recurso popular e frequentemente desejado. A Wikipedia diz (ênfase minha):
Na ciência da computação, um fechamento (...) é uma função juntamente com um ambiente de referência para as variáveis não locais dessa função. Um fechamento permite que uma função acesse variáveis fora de seu escopo lexical imediato.
Portanto, um fechamento é essencialmente um valor de função (anônimo?) Que pode usar variáveis fora de seu próprio escopo. Na minha experiência, isso significa que ele pode acessar variáveis que estão no escopo em seu ponto de definição.
Na prática, o conceito parece divergir, pelo menos fora da programação funcional. Linguagens diferentes implementam semânticas diferentes, até parece haver guerras de opiniões. Muitos programadores parecem não saber o que são fechamentos, visualizando-os como pouco mais que funções anônimas.
Além disso, parece haver grandes obstáculos ao implementar fechamentos. O mais notável é que o Java 7 deveria incluí-los, mas o recurso foi adiado para uma versão futura.
Por que os fechamentos são tão difíceis (de entender e) de realizar? Essa é uma pergunta muito ampla e vaga, portanto, deixe-me focar mais nessas perguntas interconectadas:
- Existem problemas com a expressão de fechamentos em formalismos semânticos comuns (pequeno passo, grande passo, ...)?
- Os sistemas de tipos existentes não são adequados para fechamentos e não podem ser estendidos facilmente?
- É problemático alinhar os fechamentos com uma tradução de procedimento tradicional baseada em pilha?
Observe que a pergunta se refere principalmente a linguagens processuais, orientadas a objetos e de script em geral. Tanto quanto eu sei, linguagens funcionais não têm nenhum problema.
fonte
Respostas:
Posso direcioná-lo para a página da wikipedia com problemas do Funarg ? Pelo menos é assim que as pessoas do compilador costumavam fazer referência ao problema de implementação do fechamento.
Embora essa definição faça sentido, ela não ajuda a descrever o problema de implementar funções de primeira classe em uma linguagem tradicional baseada em pilha de tempo de execução. Quando se trata de problemas de implementação, as funções de primeira classe podem ser divididas em duas classes:
O primeiro caso (funargs para baixo) não é tão difícil de implementar e pode ser encontrado até nas linguagens processuais mais antigas, como Algol, C e Pascal. C meio que contorna o problema, pois não permite funções aninhadas, mas Algol e Pascal fazem a contabilidade necessária para permitir que as funções internas façam referência às variáveis de pilha da função externa.
O segundo caso (funargs para cima), por outro lado, exige que os registros de ativação sejam salvos fora da pilha, na pilha. Isso significa que é muito fácil vazar recursos de memória, a menos que o tempo de execução do idioma inclua um coletor de lixo. Embora quase tudo seja coletado hoje em dia, exigir um deles ainda é uma decisão significativa do projeto e foi ainda mais há algum tempo.
Quanto ao exemplo específico de Java, se bem me lembro, o principal problema não era realmente implementar fechamentos, mas como apresentá-los à linguagem de uma maneira que não fosse redundante aos recursos existentes (como classes internas anônimas) e que não entraram em conflito com os recursos existentes (como exceções verificadas - um problema que não é trivial para resolver e que a maioria das pessoas não pensa a princípio).
Também posso pensar em outras coisas que tornam as funções de primeira classe menos triviais de implementar, como decidir o que fazer com variáveis "mágicas" como essa , auto ou super e como interagir com os operadores de fluxo de controle existentes, como interrupção e retorno (queremos permitir retornos não locais ou não?). Mas, no final, a popularidade recente das funções de primeira classe parece indicar que as linguagens que não as possuem geralmente o fazem por razões históricas ou devido a alguma decisão de design significativa desde o início.
fonte
ref
parâmetro"). Se o chamador encapsular todas as variáveis de interesse na estrutura, o delegado poderá ser totalmente estático, evitando a necessidade de uma alocação de heap. Os compiladores não oferecem nenhuma ajuda agradável de sintaxe para essas construções, mas o Framework poderia apoiá-las.Podemos ver como os fechamentos são implementados em C #. A escala das transformações que o compilador C # realiza deixa claro que a maneira de implementar fechamentos é bastante trabalhosa. Pode haver maneiras mais fáceis de implementar fechamentos, mas acho que a equipe do compilador C # estaria ciente disso.
Considere o seguinte pseudo-C # (recortei algumas coisas específicas do C #):
O compilador transforma isso em algo assim:
(na realidade, a variável f ainda será criada, onde f é um 'delegado' (= ponteiro de função), mas esse delegado ainda está associado ao objeto theClosureObject - deixei esta parte de fora para esclarecer aqueles que não estão familiarizados com c #)
Essa transformação é bastante maciça e complicada: considere fechamentos dentro de fechamentos e a interação de fechamentos com o restante dos recursos da linguagem C #. Eu posso imaginar que o recurso foi adiado para Java, pois o Java 7 já possui muitos recursos novos.
fonte
Para responder parte da sua pergunta. O formalismo descrito por Morrisett e Harper cobre a semântica de grandes e pequenos passos de linguagens polimórficas de ordem superior que contêm fechamentos. Existem documentos antes desses que fornecem os tipos de semântica que você está procurando. Veja, por exemplo, a máquina SECD . Adicionar referências mutáveis ou locais mutáveis a essas semânticas é simples. Não vejo problemas técnicos no fornecimento dessa semântica.
fonte