Free Pascal - Variáveis Procedurais
Autor: Professor Carlos | Publicado: 2011-05-01T23:24:00-04:00

Depois de um longo tempo afastado do blog, estamos retornando. Iremos iniciar uma série de artigos dedicados às estruturas de dados do Free Pascal. Mas antes de iniciar é necessário uma breve introdução a variáveis procedurais. 
Variáveis procedurais ou tipos procedurais são um recurso do Free Pascal que permite armazenar métodos, funções e procedimentos em variáveis. Tais variáveis podem ser normalmente tratadas, passando-as como parâmetros e chamando os métodos quando for necessário.
Para exemplificar o uso deste recurso vejamos como declarar um tipo procedural:

type
&nbsp; TFuncaoSemParametro = function(): String;
&nbsp; TFuncaoComParametro = function(x: String): String;
O primeiro exemplo declara um tipo que armazena um função que não recebe argumentos. O segundo exemplo declara um tipo que armazena uma função que recebe parâmetros.
Tipos procedurais também podem ser declarados de mais duas maneiras, como pode ser visto abaixo. O primeiro declara um tipo para armazenar um procedimento e o segundo armazena um método de uma classe:

type
&nbsp; &nbsp;TProcedimento = procedure;
&nbsp; &nbsp;TMetodo = procedure of Object;

Prosseguindo então com nosso exemplo, em seguida iremos declarar as funções:

 function AloMundo: String;
begin
&nbsp; Result := 'Alo Mundo';
end;

function AloNovamente(S: String): String;
begin
&nbsp; Result := 'Alo ' + S;
end;

Essas duas funções serão usadas como argumentos nas chamadas aos dois procedimentos seguintes, que recebem como parâmetros os tipos procedurais declarados.

procedure Primeiro(f: TFuncaoSemParametro);
begin
&nbsp; WriteLn(f());
end;

procedure Segundo(f: TFuncaoComParametro);
begin
&nbsp; WriteLn(f('Novamente'));
end;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 

Observe que tanto o procedimento Primeiro, quanto o procedimento Segundo executam a função que recebem como parâmetro. As funções chamadas irão retornar Strings que serão escritas no console através de writeln.
Para testar a funcionalidade apenas chame os procedimentos assim:

Primeiro(@AloMundo);
Segundo(@AloNovamente);

O símbolo @ converte a variável em um ponteiro. É desta forma que a função é passada como parâmetro.
É importante observar que o compilador  verifica se a função ou o procedimento que está sendo passado como parâmetro corresponde exatamente  ao esperado, ou seja, possui os mesmos parâmetros, o mesmo tipo de  retorno, etc.
O mecanismo usado pelos eventos de componentes da biblioteca do Lazarus é exatamente este. Veja como pode ser criado um componente dinamicamente e como atribuir um método a um evento de um TButton no post Lazarus - Criando componentes em run-time.
A seguir o código completo da aplicação console:

program procvar;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes
  { you can add units after this };
type
  TFuncaoSemParametro = function(): String;
  TFuncaoComParametro = function(x: String): String;

function AloMundo: String;
begin
  Result := 'Alo Mundo';
end;

function AloNovamente(S: String): String;
begin
  Result := 'Alo ' + S;
end;

procedure Primeiro(f: TFuncaoSemParametro);
begin
  WriteLn(f());
end;

procedure Segundo(f: TFuncaoComParametro);
begin
  WriteLn(f('Novamente'));
end;

{$R *.res}

begin
  Primeiro(@AloMundo);
  Segundo(@AloNovamente);
  ReadLn;
end.

Atualizado em 03/05/2011.