Módulos e visibilidade
module e unit, public/private/protected, region, namespace e using, initialization e finalization.
module#
Um arquivo .fxm declara um módulo. Não há interface nem implementation: cada declaração diz se é public ou private, e a omissão é private.
program Main;
uses Geometry;
begin
WriteLn('lados: ', Geometry.Sides);
WriteLn('área: ', SquareArea(5));
WriteLn('id: ', NextId);
WriteLn('id: ', NextId);
// Square(3) aqui seria erro: é private no módulo
end.module Geometry;
// Um module não tem interface nem implementation: cada declaração diz se é
// public ou private, e a omissão é private.
public const
Sides = 4;
private function Square(const X: Int32): Int32;
begin
Exit(X * X);
end function;
public function SquareArea(const ASide: Int32): Int32;
begin
Exit(Square(ASide));
end function;
// region agrupa e pode trocar a omissão de dentro dela
public region 'Counters';
var
Calls: Int32;
function NextId: Int32;
begin
Inc(Calls);
Exit(Calls);
end function;
end region;
initialization
Calls := 100;
end.lados: 4
área: 25
id: 101
id: 102module Sales;
public type
TCustomer = class(TObject) … end class;
private function Helper: Int32; // só este módulo enxerga
begin … end function;
public function Total: Int32; // todo mundo enxerga
begin … end function;
initialization
…
finalization
…
end.- O corpo
begin…end.de um programa é a inicialização dele; o encerramento sai dasfinalizationdos módulos, na ordem inversa da carga. SystemeSysInitentram implicitamente em todo programa.- A forma
unitclássica, cominterface/implementation, continua aceita. - Recursão mútua sem
interface:forward. - O corpo de um método não leva visibilidade; ela vem da classe.
Os três níveis#
| Visibilidade | Outro módulo do projeto | Exportado no .fxd/.dll de um package |
|---|---|---|
private | não | não |
protected | sim | não |
public | sim | sim |
protected só faz diferença num package: é o que permite que dois módulos da mesma biblioteca se enxerguem sem publicar o que não é parte do contrato. Num program ou library não existe "fora", e protected equivale a public.
region#
region agrupa declarações e pode trocar a omissão de dentro dela. O rótulo em cadeia é para a IDE; o compilador o ignora. Fecha-se com end; ou end region;.
public region 'Counters'; // dentro dela, a omissão passa a ser public
var Calls: Int32;
function NextId: Int32;
begin … end function;
end region;
private region; // e pode voltar a fechar
var Hidden: Int32;
end region;Uma região aninhada herda a omissão da de fora.
rad_region#
rad_region 'rótulo'; … end rad_region; é a região que uma ferramenta escreve e reescreve; o designer do RAD a usa para os campos e os eventos de um formulário. É puramente léxica: não abre escopo nem visibilidade, e o conteúdo vale como se estivesse solto ali. Vale no corpo do módulo e dentro de uma classe. O rótulo é obrigatório (é por ele que a ferramenta acha a região) e o fecho exige o qualificador, para o fim não depender de contagem.
namespace e using#
namespace "Nome"; … end namespace; e using "Nome"; são só visibilidade: os nomes seguem únicos no módulo e nada muda no binário. Há três formas de alcançar um nome guardado num namespace:
- qualificando pela unit:
UNs."Enderecos".TEndereco; - abrindo com
using:using "Enderecos";e depoisTEndereco; - de dentro dele: quem está em
"A"."B"enxerga o de"A".
O using vale no escopo em que foi escrito: dentro de uma região, só ali; no módulo, no módulo inteiro. Há formas curtas:
procedure "System.Az".Teste; // declara direto no namespace, sem abrir bloco
begin … end procedure;
using "System.Az" do // o using vale só para o próximo item
procedure UsaUmaVez;
begin
WriteLn(Dobro(21));
end;
"System.Az".Teste(); // citar qualificado, num comandoUm nome entre aspas duplas é um nome de namespace, não uma cadeia.
uses#
uses System.Remainder, System.WCL, Unit1;uses traz módulos pelo nome, procurando ao lado do projeto e nas pastas de SourcePath. Os módulos da RTL têm nomes com pontos (System.DB.SqLite). Um nome pode ser qualificado pelo módulo (Geometry.Sides), o que resolve colisões.
initialization e finalization#
initialization roda quando o módulo é carregado; finalization roda no encerramento, na ordem inversa da carga. Num late module a initialization roda por último e a finalization, primeiro (veja Metaprogramação).
Num class constructor, o código roda uma vez no arranque, e é podado se o tipo morrer na eliminação de código não usado.