Rotinas
procedure e function, parâmetros, sobrecarga, valores padrão, tipos procedurais e chamadas externas.
Procedimentos e funções#
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#
| Modo | Efeito |
|---|---|
| (por valor) | o parâmetro é uma cópia |
const | só leitura; objetos e cadeias não geram contagem de referência à toa |
constref | só leitura, e sempre passado por referência |
var | passado por referência; o valor entra e sai |
out | passado por referência; só sai (o valor de entrada é descartado) |
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:
procedure Greet(const AName: UString = 'mundo');
begin
WriteLn('olá, ', AName);
end procedure;
Greet; // olá, mundo
Greet('Ana'); // olá, AnaUm 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.
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.Swap: 4 3
17 = 5 * 3 + 2
inteiro 42 / texto abc
Apply: 5
Twice: 42Corpo 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):
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#
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 objectguarda um método junto com o objeto: é o tipo dos eventos (OnClick).reference toguarda 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#
function GetTickCount: UInt32; stdcall; external 'kernel32.dll' name 'GetTickCount';
function Soma(A, B: Int32): Int32; stdcall; external 'minha.dll' index 3;| Palavra | Efeito |
|---|---|
stdcall cdecl register safecall pascal | convenção de chamada |
external 'dll' name 'símbolo' | importa por nome (inclusive renomeado) |
external 'dll' index N | importa por ordinal |
forward | declara adiantado; é o que permite recursão mútua |
inline | pede a expansão no ponto da chamada |
abi_win / abi_posix | força a ABI da rotina, seja qual for a plataforma |
varargs | lista 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.