Pascal – array de argumentos

A definição da linguagem Pascal, desde os seus primórdios, estabelece regras bastante rígidas acerca da passagem de argumentos a uma função ou procedimento. No seu conjunto, uma das consequências destas regras é a impossibilidade de se implementarem funções variádicas, isto é, funções sem um número definido de argumentos. Na prática, isto traduz-se na possibilidade de se poder fornecer virtualmente uma infinidade de argumentos à função, não havendo a restrição de ser necessário passar apenas N argumentos em determinada ordem e com determinados tipos.

Várias linguagens permitem a implementação de funções variádicas, como por exemplo C e até Haskell (com recurso a alguns truques na definição de tipos de dados e suas heranças).

 O facto de Pascal não permitir a implementação de funções variádicas pode suscitar algumas dúvidas. Métodos standard que formam a base do Pascal são aparentemente variádicos, como o writeln e o readln. No entanto, estes métodos não são exactamente funções ou procedimentos. A sua construção está a cargo do próprio compilador em compile time, não sendo uma característica da linguagem.

Todavia, o rio não encontra a sua foz neste ponto. Apesar de esta funcionalidade não ser permitida, existe uma forma de a simular. Compiladores e dialectos mais recentes, como o Delphi e o Free Pascal, permitem a passagem de arrays de argumentos, a qual tem por princípio a passagem de arrays abertos, conceito que será brevemente revisto.

Todo o código presente neste artigo foi compilado recorrendo ao Free Pascal Compiler, versão 2.6.2, em ambiente Windows®, sendo totalmente portável para outras plataformas.

Passagem de open arrays

Quando o Pascal foi dado a conhecer ao mundo em 1971, era obrigatória a definição de tipos de dados com a palavra reservada type para se poder passar um array como argumento. Mais ainda, este array era estático, com uma dimensão bem definida, uma vez que na altura não fora ainda introduzido o conceito de array dinâmico.

Com o evoluir da linguagem, este conceito foi implementado, e pela primeira vez os arrays não necessitavam de ter uma dimensão bem definida – esta podia ser controlada em runtime. Dadas as suas características, tornou-se uma forma de criar o equivalente a pequenas listas ligadas com muito maior segurança uma vez que a gestão de recursos não fica a cargo do programador.

Da mesma forma, deixou de ser obrigatória a criação de tipos de dados para a passagem de arrays em argumentos. Se antes era necessário um tipo para cada dimensão, e um procedimento para cada tipo, o trabalho do programador fora imensamente facilitado.

Por exemplo, pode-se receber um array de números inteiros de pequena dimensão e sem sinal da seguinte forma:

function Average(list : array of byte) : real;

Recorrendo às funções Low e High, e mais recentemente com a estrutura de repetição for-in, torna-se simples iterar os elementos do array.

function Average(list : array of byte) : real
var i : byte;
begin
    Average := 0.0;
    for i:=Low(list) to High(list) do
        Inc(Average, list[i]);
    Average := Average / Length(list);
end;

Outra característica de elevado interesse é o facto de se poder passar parcialmente um array. Vejamos o seguinte exemplo:

var xs : array[1..20] of byte;
// ...
writeln(Average(xs[10..20]):0:3);

Neste caso, apenas é do nosso interesse calcular a média da segunda metade do array xs. Portanto, definimo-lo com a sintaxe xs[10..20]. Desta forma, apenas os elementos do índice 10 ao 20, inclusive, são passados à função Average.

Todas estas funcionalidades compõe aquilo a que se denomina de passagem de arrays abertos (ou, mais correctamente em inglês, open arrays): a possibilidade de receber um array sem conhecimento prévio da sua dimensão, bem como a possibilidade de realizar a passagem parcial de um array.

Publicado na edição 45 (PDF) da Revista PROGRAMAR.