Fenner
A linguagem

Rotinas

procedure e function, parâmetros, sobrecarga, valores padrão, tipos procedurais e chamadas externas.

Procedimentos e funções#

Fenner
function Fib(N: Int32): Int32;
begin
  if N < 2 then
    Result := N
  else
    Result := Fib(N - 1) + Fib(N - 2);
end function;

Uma function devolve valor por Result ou por Exit(valor); uma procedure não devolve. O fecho pode ser qualificado (end function;, end procedure;), e o compilador confere que combina com a abertura.

Parâmetros#

ModoEfeito
(por valor)o parâmetro é uma cópia
constsó leitura; objetos e cadeias não geram contagem de referência à toa
constrefsó leitura, e sempre passado por referência
varpassado por referência; o valor entra e sai
outpassado por referência; só sai (o valor de entrada é descartado)
Fenner
procedure Swap(var A, B: Int32);
var
  Temp: Int32;
begin
  Temp := A;
  A := B;
  B := Temp;
end procedure;

procedure Split(const Value, Divisor: Int32; out Quotient, Remainder: Int32);
begin
  Quotient := Value div Divisor;
  Remainder := Value mod Divisor;
end procedure;

Valores padrão são aceitos, e o parâmetro com padrão pode ser omitido na chamada:

Fenner
procedure Greet(const AName: UString = 'mundo');
begin
  WriteLn('olá, ', AName);
end procedure;

Greet;          // olá, mundo
Greet('Ana');   // olá, Ana

Um vetor aberto (const A: array of Int32) aceita qualquer vetor do tipo e um literal [1, 2, 3]; array of const aceita valores de tipos variados, e é como o Format recebe seus argumentos.

Sobrecarga#

overload permite várias rotinas com o mesmo nome. O compilador escolhe pelo tipo dos argumentos, em três passadas: correspondência exata, correspondência frouxa e, por fim, com conversão. Numa classe, o conjunto do descendente se junta ao do ancestral.

routines.fxp
program Routines;

type
  TOperation = function(A, B: Int32): Int32;

function Add(A, B: Int32): Int32;
begin
  Exit(A + B);
end function;

function Twice(const X: Int32): Int32;
begin
  Exit(X * 2);
end function;

// var devolve ao chamador; out só devolve
procedure Swap(var A, B: Int32);
var
  Temp: Int32;
begin
  Temp := A;
  A := B;
  B := Temp;
end procedure;

procedure Split(const Value, Divisor: Int32; out Quotient, Remainder: Int32);
begin
  Quotient := Value div Divisor;
  Remainder := Value mod Divisor;
end procedure;

// sobrecarga: o compilador escolhe pelo tipo dos argumentos
function Describe(const N: Int32): UString; overload;
begin
  Exit('inteiro ' + IntToUStr(N));
end function;

function Describe(const S: UString): UString; overload;
begin
  Exit('texto ' + S);
end function;

function Apply(Operation: TOperation; A, B: Int32): Int32;
begin
  Exit(Operation(A, B));
end function;

var
  X, Y, Q, R: Int32;
begin
  X := 3;
  Y := 4;
  Swap(X, Y);
  WriteLn('Swap: ', X, ' ', Y);

  Split(17, 5, Q, R);
  WriteLn('17 = 5 * ', Q, ' + ', R);

  WriteLn(Describe(42), ' / ', Describe('abc'));
  WriteLn('Apply: ', Apply(@Add, 2, 3));
  WriteLn('Twice: ', Twice(21));
end.
Saída
Swap: 4 3
17 = 5 * 3 + 2
inteiro 42 / texto abc
Apply: 5
Twice: 42

Corpo curto com =>#

Dentro da declaração de um tipo, um método de uma linha pode ser escrito com => e um comando (que pode ser um begin…end):

Fenner
type
  TSquare = class(TObject)
  private
    FSide: Int32;
  public
    function Area: Int32; => Exit(FSide * FSide);
  end class;

O => vale na declaração, dentro do corpo do tipo; não existe a forma separada da implementação. Também é a forma dos class operator e das funções anônimas (veja Lambdas).

Tipos procedurais#

Fenner
type
  TOperation = function(A, B: Int32): Int32;                // rotina comum
  TNotifyEvent = procedure(const ASender: TObject) of object;  // método de objeto
  TBinary = reference to function(A, B: Int32): Int32;      // função anônima

function Apply(Operation: TOperation; A, B: Int32): Int32;
begin
  Exit(Operation(A, B));
end function;

Apply(@Add, 2, 3);
  • Um tipo procedural simples guarda o endereço de uma rotina (@Add).
  • of object guarda um método junto com o objeto: é o tipo dos eventos (OnClick).
  • reference to guarda uma função anônima, inclusive com captura de variáveis.

Os eventos têm uma forma própria de chamada guardada (Evento!(args)) e um tipo Delegate que se desliga sozinho quando o alvo morre; veja Lambdas, eventos e async.

Convenções, DLLs e rotinas externas#

Fenner
function GetTickCount: UInt32; stdcall; external 'kernel32.dll' name 'GetTickCount';
function Soma(A, B: Int32): Int32; stdcall; external 'minha.dll' index 3;
PalavraEfeito
stdcall cdecl register safecall pascalconvenção de chamada
external 'dll' name 'símbolo'importa por nome (inclusive renomeado)
external 'dll' index Nimporta por ordinal
forwarddeclara adiantado; é o que permite recursão mútua
inlinepede a expansão no ponto da chamada
abi_win / abi_posixforça a ABI da rotina, seja qual for a plataforma
varargslista variável de argumentos, para C

Uma library exporta com a cláusula exports; veja Interoperabilidade.

Dicas de otimização#

pure, force, discardable, preserve e noreturn dizem ao compilador o que a rotina promete. Uma função pure cuja chamada tem o resultado jogado fora some na compilação; noreturn diz que a chamada não volta, e o que vem depois é inalcançável. Estão na página de diretivas.