Sub-rotina aninhada

Em programação, uma sub-rotina aninhada (ou função aninhada) é uma sub-rotina encapsulada dentro de outra. A sub-rotina aninhada é acessível apenas na sub-rotina que a encapsula, ou pelas sub-rotinas aninhadas diretamente, ou indiretamente dentro da mesma sub-rotina encapsuladora. Teoricamente o aninhamento pode ser ilimitado, mas, na prática, apenas alguns níveis são aceitos, dependendo da implementação.

Essa técnica é uma forma de encapsulamento, e permite dividir tarefas procedimentais em sub tarefas que fazem sentido somente localmente. Em linguagens que suportam essa técnica, são geralmente aceitos outros tipos de aninhamento, como o aninhamento de constantes e tipos de dado.

Quando disponíveis, as sub-rotinas aninhadas são uma abordagem comum para implementar algoritmos com laços de repetição em linguagens funcionais.

O suporte a funções aninhadas varia entre as linguagens de programação. Enquanto é encontrado em linguagens estruturadas mais antigas, como C, ALGOL, Simula 67 e Pascal, além de ser amplamente utilizado no JavaScript, sua presença é comum em linguagens dinâmicas e funcionais. No entanto, não é suportado em algumas linguagens amplamente utilizadas, como C++.

Outras linguagens de programação oferecem vantagens semelhantes. Por exemplo, uma função lambda também permite que uma função seja definida em uma função (bem como noutro local) e permite a ocultação e o encapsulamento de dados semelhantes.

O escopo de uma função aninhada é o bloco que a contém, seja ele um bloco de função ou um bloco no corpo de uma função. Fora desse bloco, a função aninhada não é visível e não pode ser chamada pelo nome.

Uma função aninhada tem acesso aos identificadores (nomes de funções, variáveis, tipos, classes) declarados em qualquer bloco envolvente, exceto quando esses identificadores são mascarados por declarações internas com os mesmos nomes.

É possível declarar funções aninhadas dentro de outras funções, recursivamente, formando uma estrutura profundamente aninhada. Uma função profundamente aninhada pode acessar identificadores declarados em todos os blocos que a envolvem, incluindo funções anexas.

Por exemplo, se uma função PAI contém uma função FILHA, a função FILHA pode acessar as variáveis de PAI. Se PAi está dentro de outra função AVÓ, então FILHA também pode acessar as variáveis de AVÓ.

  1. Criação de Clausura: Em algumas situações, funções aninhadas podem criar uma clausura. Isso acontece quando uma função aninhada pode ser utilizada fora do contexto original, retendo acesso às variáveis externas.
  2. Acesso ao Ambiente Original: Quando uma função aninhada é usada fora de sua função envolvente, ela mantém acesso ao ambiente da função original.
  3. Vida do Fechamento: A função envolvente deve permanecer ativa até que a última referência ao fechamento seja eliminada.
  4. Problema Funarg: O problema funarg surge quando variáveis locais não estáticas referenciadas por fechamentos não podem ser alocadas na pilha. Isso pode complicar a geração e análise de código, especialmente em casos de aninhamento em vários níveis, compartilhando diferentes partes do ambiente.

Essas considerações são uma das razões pelas quais as funções aninhadas não são implementadas em algumas linguagens mais simples.

Segue um exemplo em Pascal:

function E(x: real): real
    function F(y: real): real
    begin
        F := x + y
    end
begin
    E := F(3)
end

A função F está aninhada em E (note que x é visível em F, enquanto y é invisível fora de F).

Linguagens que suportam sub-rotinas aninhadas incluem:

Referências

  1. «Functions - Nested Functions». D Programming Language 2.0 (em inglês). Digital Mars. Consultado em 9 de julho de 2008 
  2. «Nested Functions». Using the GNU Compiler Collection (GCC) (em inglês). GNU Project. Consultado em 6 de janeiro de 2007