PROCEDURES E FUNCTIONS


  O Pascal é uma linguagem estruturada, diferente do Basic que não é. No Basic, o código do programa é uma lista enorme, sem apresentar divisão textual da lógica do programa. Já em uma linguagem estruturada como o Pascal, o programa é dividido em módulos ou sub-rotinas. Dessa meneira, o código fica mais legível, além de ser mais fácil portar, dar manutenção e ser mais confiável.

  Uma sub-rotina é uma porção de código para realizar uma tarefa especifica. Ela pode ser definida como um grupo de comandos, constituindo um trecho de algoritmo, com uma função bem definida e o mais independente possível em relação ao resto do algoritmo.

  O ideal é que os módulos não sejam grandes demais, pois senão acabam sendo multifuncionais e de difícil compreensão, de modo que o modulo deve ser implementado apenas as estruturas de dados necessários para atingir ao objetivo do modulo.

  Uma sub-rotina é declarada da seguinte forma:
subrotina NOME(lista-de-parâmetros)
  declarações dos objetos locais das sub-rotinas
  comandos das sub-rotinas
fimsubrotina
A lista de parâmetros é opcional. Caso seja usada elas podem ser de duas formas:
Fonte: Wikipedia - Modularidade

  Tanto a procedure como a function são subrotinas que tem como missão realizar alguma tarefa específica. A diferença entre procedure e funtion é que a function retorna algum valor, enquanto que a procedure não retorna.

  Para enter bem a diferença entre procedure e function, vejamos duas situações distintas:   No caso da impressão de uma mensagem, não é neessário o retorno de qualquer informação. Assim, pode-se utilizar uma prodecure. Já no caso do cálculo do produto de dois números, é desejável o retorno do valor calculado. Nesse caso, deve-se utilizar uma funtion.

  O exemplo a seguir ilustra o uso de uma procedure e de uma function:
var prod : integer;

procedure mostra_mensagem();
begin
  writeln('Ola. Bem vindo ao programa de procedures e functions.');
end;

function calcula_produto(a, b : integer) : integer;
begin
  calcula_produto := a * b;
end;

begin
  mostra_mensagem();
  prod := calcula_Produto(4,3);
  writeln('Resultado de 4 x 3: ',&prod);
end.
Saída:
Ola. Bem vindo ao programa de procedures e functions.
Resultado de 4 x 3: 12

  Sintaxe para a procedure:

procedure nome(lista de parametros);
lista de variaveis locais
begin
código
end

  Sintaxe para a function:

function nome(lista de parametros) : tipo_de_retorno;
lista de variaveis locais
begin
código
end

  Na lista de parâmetros, os tipos iguais são separados por vírgula, enquanto que os tipos diferentes são separados por ponto e vírgula. Ex:

procedure calcula(a, b : integer; c, d : real);

  O exemplo a seguir ilustra o uso completo da sintaxe de function:
function funcao_X(a : integer; b : real) : real;
var c : real;
begin
  c := 0.45;
  funcao_X := real(a) * b * c;
end;
  Obs: as variáveis locais (variáveis declaradas dentro de uma função ou procedure) tem duração limitada ao tempo de execução da sub-rotina. Ou seja, assim que essa sub-rotina encerra sua execução, esta variável é descartada juntamente com a informação contida nela.

  No exemplo anterior, a variável "c" é descartada assim que a function "funcao_X" termina sua execução.

  Já as variáveis globais (declaradas no corpo principal do programa) tem duração longa e só são descartadas quando o programa termina sua execução. Elas estão o tempo todo disponíveis e podem ser acessadas a partir de sub-rotinas.

  É possível declarar variáveis locais com o mesmo nome de uma variável global. Entretanto, a variável local terá precedência sobre a variável global dentro da sub-rotina, ou seja, o valor acessado é o da variável local. Ex:
var x, y : integer;

procedure teste();
var x : integer;
begin
  x := 4;
  writeln('Valor de X:',&x);
  writeln('Valor de Y:',&y);
end;

begin
  x := 2;
  y := 5;

  teste();

  writeln('Valor de X:',&x);
  writeln('Valor de Y:',&y);
end.
Saída:
Valor de X:4
Valor de Y:5
Valor de X:2
Valor de Y:5

  Passagem por referência e valor

  A esta altura, o leitor já deve ter perguntado o seguinte: e se eu alterar o valor de uma variável passada como parâmetro para uma sub-rotina, o que acontece? Essa alteração é refletida na variável que foi utilizada na chamada da função?

  Bem, na verdade as mudanças podem ou não refletir na variável utilizada na chamada da função, dependendo de como os parâmetros são declarados.

  Conforme visto anteriormente, há dois tipos de passagem de parâmetros: por valor ou por referência. Na passagem por valor, é passada uma cópia da variável original e assim, qualquer alteração dessa variável dentro da função NÃO irá refletir na variável original. Já na passagem por referência, a variável original é passada diretamente para dentro da sub-rotina e qualquer alteração IRÁ refletir na variável original.

  Até o presente momento, todos os parâmetros utilizados nos exemplos fazem passagem por valor (ou cópia). Para realizar a passagem por referência, deve-se utilizar a palavra reservada "var" antes da declaração do parâmetro. Ex:
var x : integer;

procedure valor(a : integer);
begin
  a := 10;
end;

procedure referencia(var a : integer);
begin
  a := 15;
end;

begin
  x := 5;
  writeln('Valor de X:',&x);

  valor(x);
  writeln('Valor de X:',&x);

  referencia(x);
  writeln('Valor de X:',&x);
end.
Saída:
Valor de X:5
Valor de X:5
Valor de X:15

  Obs: ao utilizarmos o mesmo nome da variável utilizada na chamada da função nos parâmetros da sub-rotina, terá o mesmo efeito que a declaração de uma variável local, salvo quando há utilização de passagem por referência. Assim, ao substituirmos todas as variáveis "a" por "x" no exemplo anterior, iremos obter as mesmas respostas.

  Procedures e functions que retornam mais de um valor

  Conforme visto até aqui, as procedures não retornam valor e as functions retornam apenas um valor. E se eu quiser retornar mais valores? Como fazer?
  A primeira solução é utilizar parâmetros que passam valor por referência. Assim, é só modificar o valor desses parâmetros, que o retorno será feito. Ex:
procedure retorna_dados (var nome : string; idade : integer; peso : real);
begin
  nome := 'Pedro';
  idade := 31;
  peso := 80.0;
end;

var nome : string;
    idade : integer;
    peso : real;

begin
  retorna_dados(nome, idade, peso);

  writeln('Nome: ', nome);
  writeln('Idade: ', idade);
  writeln('Peso: ', peso:2:1);  { Formatação de escrita um número real: no_casas_int:no_casas_fração }
end.
Saída:
Nome: Pedro
Idade: 21
Peso: 80.0

  A segunda solução é criar um tipo de dados composto, utilizando o "type". Através de uma funtion, iremos retornar dados desse tipo composto criado. Ex:
type ficha_mod = record
       nome : string[20];
       idade : integer;
       peso : real;
      end;

function retorna_dados : ficha_mod;
begin
  retorna_dados.nome := 'Pedro';
  retorna_dados.idade := 31;
  retorna_dados.peso := 80.0;
end;

var ficha : ficha_mod;

begin
  ficha := retorna_dados;

  writeln('Nome: ', ficha.nome);
  writeln('Idade: ', ficha.idade);
  writeln('Peso: ', ficha.peso:2:1);
end.
Saída:
Nome: Pedro
Idade: 21
Peso: 80.0


/MARMSX/CURSOS/PASCAL