Documento: Passagem de Parâmetros


A passagem de parâmetros é um recurso fundamental da linguagem AdvPL. Quando se utiliza uma função, o AdvPL permite que sejam passados valores de dados ou referências de variáveis para ela. Esta capacidade permite que sejam criadas rotinas genéricas e flexíveis, que podem processar os parâmetros passados, independentemente da rotina que as invocou, para executar várias operações específicas, de acordo com os parâmetros passados.

A passagem de parâmetros envolve dois aspectos. O primeiro refere-se à rotina que invocou outra e passou um certo número de argumentos. O segundo refere-se à rotina que foi chamada e espera receber um determinado número de parâmetros. Note que o número de argumentos passados pode ser menor que o número de parâmetros esperados.

Os parâmetros são recebidos na mesma ordem na qual os argumentos são passados. Entretanto, pode-se omitir ou pular parâmetros que não se deseja passar ou não são necessários. Por exemplo:

// Função invocada aguarda 4 parâmetros
FUNCTION Teste(cPar1, cPar2, cPar3, cPar4)

// No momento da invocação da função, passa-se apenas 2 argumentos
Teste("Teste 1", , "Teste 3")

Nesse exemplo, os valores dos parâmetros recebidos pela função Teste seriam:

  • Teste 1
  • NIL
  • Teste 3
  • NIL

Os parâmetros funcionam como receptores dos argumentos. Ou seja, cada valor ou referência de um argumento passado é atribuído em um parâmetro esperado. Quando um parâmetro não recebe um argumento, ele assume automaticamente o valor NIL (ausência de dado), como demonstrado no exemplo anterior.

Há duas formas de se realizar a passagem de parâmetros: por Valor ou por Referência.

  • por Valor

A passagem de parâmetros por valor significa que o argumento passado é avaliado e o valor do seu resultado é copiado para o parâmetro correspondente na função invocada. Qualquer alteração no valor do parâmetro recebido pela função tem abrangência apenas local. Isto é, a alteração é perdida quando a função é finalizada, mantendo-se o valor original do argumento enviado para a função.

No AdvPL, por definição, quando se define uma função especificando a lista de argumentos entre parênteses, todas as variáveis, expressões e elementos de arrays (matrizes ou vetores) são passados por valor, incluindo variáveis contendo referências a arrays (matrizes ou vetores), objetos e blocos de código.

A importância da passagem de parâmetros por valor reside no fato de que a função invocada não altera o valor dos dados da rotina que a invocou. Os valores dos parâmetros recebidos até podem ser alterados pela função invocada. Porém, essa alteração não se refletirá no conteúdo dos argumentos passados pela rotina que invocou a função.

  • por Referência

A passagem de parâmetros por referência significa que apenas uma referência ao valor do argumento é passada para a função invocada, ao invés de uma cópia do valor do argumento. O parâmetro recebido, portanto, refere-se à mesma localização de memória do parâmetro passado. Caso a função invocada altere o valor desse parâmetro, o valor do argumento passado também será alterado.

Todas as variáveis, com exceção daquelas que se referem à campos de uma tabela, podem ser passadas por referência. Para isso, devem ser precedidas pelo símbolo arroba ( @ ) quando forem passadas como argumentos. O símbolo arroba representa o operador de passagem por referência. Por exemplo:

nNum1 := 2
nNum2 := 2

TesteRef(@nNum1, nNum2)

// Função invocada
FUNCTION TesteRef(nPar1, nPar2)

               nPar1 := nPar1 * nPar2
               nPar2 := nPar1 + nPar2

RETURN

Caso o usuário mostrasse na tela o valor das variáveis nNum1 e nNum2 após a execução da função, eles seriam 4 e 2, respectivamente.

Esse exemplo mostra que se uma variável for passada por referência, o seu conteúdo é alterado caso a função invocada altere o respectivo parâmetro recebido. De fato, após a execução da função TesteRef(), o conteúdo da variável nNum1, que era 2, passa a ser 4, pois ela foi passada por referência. Por outro lado, o conteúdo da variável nNum2 manteve-se o mesmo, pois ela foi passada por valor.

A passagem de parâmetros por referência pode ser perigosa, pois os parâmetros recebidos podem alterar inadvertidamente o valor das variáveis passadas como argumentos, causando grande confusão e erros na aplicação. Por esse motivo, a passagem de parâmetros por referência deve ser utilizada apenas em casos especiais, quando for realmente necessária. Um exemplo típico é o da função FREAD(), que será estudada posteriormente. Essa função deve receber parâmetros passados por referência.


Passagem de Arrays (Matrizes) e Objetos como parâmetros

Pela sintaxe da passagem de parâmetros das funções, as variáveis contendo referências à arrays (matrizes) e objetos são passadas por valor. Entretanto, se um array é passado para uma rotina por valor e a rotina invocada alterar o valor de um dos seus elementos, esta mudança se refletirá no elemento original da matriz, tornando-se definitiva. Por exemplo:

aVetor := { 1, 2, 3 }  // Declara a variável array

Elemento(aVetor, 1)  // Executa a função Elemento()

// Função Elemento()
FUNCTION Elemento(aMat, i)
               // Altera o valor do primeiro elemento do array original
               aMat[1] := 2 * aMat[i]
RETURN NIL

Nesse exemplo, após a execução da função Elemento() o conteúdo do array foi alterado para { 2, 2, 3 }.

Todavia, se a referência de um array for atribuído a uma variável e esta for passada para uma rotina por valor, qualquer alteração realizada dentro da função invocada não terá efeito permanente, sendo desconsiderada quando a função invocada for finalizada. Consequentemente, o valor original da variável será mantido. Por exemplo:

aVetor := { 1, 2, 3 }  // Declara a variável

Matriz(aVetor)  // Executa a função Matriz()

// Função Matriz()
FUNCTION Matriz (aVetor)
               // Altera o valor da variável aVetor
               aVetor := { 10, 20, 30 }
RETURN NIL

Nesse exemplo, após a execução da função Matriz() o conteúdo do array foi mantido em { 1, 2, 3 }.

Finalmente, se uma variável contendo uma referência a um array ou objeto for passada por referência, qualquer alteração na referência da variável será mantida após o término da função invocada. Por exemplo:

aVetor := { 1, 2, 3 }  // Declaração da variável

Matriz(@aVetor)  // Executa a função Matriz()

// Função Matriz()
FUNCTION Matriz(aVetor)
               // Altera o valor da variável aVetor
               aVetor := { 10, 20, 30 }
RETURN NIL

Nesse caso, a alteração realizada pela função Matriz() no conteúdo do array foi mantida. Os valores do array foram alterados de { 1, 2, 3 } para { 10, 20, 30 }.

  • Sem rótulos