Uma das discussões mais antigas e recorrentes nos fóruns de Delphi e Pascal gira em torno de uma verificação simples: devemos usar Assigned(Variavel) ou Variavel <> nil?
À primeira vista, ambas parecem fazer exatamente a mesma coisa: verificar se um ponteiro ou referência de objeto contém um endereço válido de memória. Muitos desenvolvedores escolhem um ou outro baseando-se puramente em legibilidade ou hábito (“Assigned é mais elegante” vs “<> nil é mais explícito“).
No entanto, há uma razão técnica profunda para a existência da função Assigned, e ela remonta às origens do Delphi 1 e à arquitetura da VCL. Entender isso é crucial, especialmente se você desenvolve componentes.
O Básico: Ponteiros Normais e Objetos
Para ponteiros simples e instâncias de objetos, a verificação tradicional:
if MeuObjeto <> nil then
// faz algo
…funciona perfeitamente. O compilador gera um código de máquina eficiente que compara o valor do ponteiro com zero. Assumindo que a variável foi inicializada corretamente (como nil), essa instrução cumpre seu papel.
Então, por que a Borland (hoje Embarcadero) introduziu a função Assigned?
O Pulo do Gato: Method Pointers
A necessidade do Assigned surgiu com a introdução dos Method Pointers (Ponteiros de Método), que são a base do sistema de eventos do Delphi (como o OnClick, OnChange, etc).
Diferente de um ponteiro simples que guarda apenas um endereço de memória, um Method Pointer é uma estrutura composta por dois ponteiros:
- Code Pointer: O endereço do método (código) a ser executado.
- Data Pointer: A instância específica do objeto (o
Self) onde esse método será executado.
Em termos de memória, é como se fosse um record com dois campos.
O Problema do Design-Time
Aqui é onde a mágica (e o perigo) acontece. Quando você está desenhando uma tela no IDE do Delphi, o “VCL Form Designer” precisa realizar alguns truques.
Para gerenciar as propriedades no Object Inspector sem disparar eventos acidentalmente, o Designer do Delphi, às vezes, atribui valores internos a esses Method Pointers. Especificamente, ele pode preencher a parte do Data Pointer (a instância) com um índice interno ou marcador, deixando o Code Pointer vazio ou nulo.
Se você tentar verificar um evento usando a sintaxe padrão:
// Tenta verificar se ambos os ponteiros da estrutura são nil
if @FOnClick <> nil then
FOnClick(Self);
Essa verificação (<> nil) compara a estrutura inteira (ambos os ponteiros). Se o Designer do Delphi tiver preenchido a parte da instância com seus dados internos, a comparação resultará em True (diferente de nil), mesmo que não exista código real para executar. O resultado? O componente tenta chamar um método que não existe e BOOM: Access Violation ou comportamento indefinido dentro da IDE.
A Solução: Assigned
A função Assigned foi criada especificamente para resolver esse cenário. Ela não verifica a estrutura inteira do ponteiro de método.
Ao usar Assigned(FOnClick), o compilador gera código que verifica apenas o Code Pointer (o endereço do código), ignorando o ponteiro da instância.
Isso garante que:
- Se o evento foi atribuído no código, ele verifica o endereço do método corretamente.
- Se o Designer do Delphi “sujou” a parte da instância para uso interno, o
Assignedignora isso e retornaFalsecorretamente (já que o endereço do código ainda é nil), prevenindo o erro.
Resumo Técnico
Ao nível de assembly e geração de código:
if @Event <> nil: Compara os dois blocos de memória (Code + Data) contra zero. Perigoso para componentes.if Assigned(Event): Compara apenas o bloco de memória do código contra zero. Seguro para componentes.
Veredito: Quando usar qual?
Com base na arquitetura do compilador explicada por Allen Bauer (um dos arquitetos originais do Delphi), a regra de ouro é:
- Para Eventos (Method Pointers): O uso de
Assignedé obrigatório. Se você está escrevendo um componente e vai disparar um evento (FOnClick), você deve usarif Assigned(FOnClick). Não façaif @FOnClick <> nil. - Para Objetos e Ponteiros Comuns: É uma questão de preferência.
Assigned(Obj)eObj <> nilfuncionam de forma idêntica e segura.- Alguns preferem
Assignedpela consistência com os eventos. - Outros preferem
<> nilpara deixar claro que estão lidando com ponteiros e memória, ou porque acham mais legível ver a comparação explícita.
- Alguns preferem
Conclusão
Embora pareça apenas “açúcar sintático”, o Assigned é uma ferramenta vital para a estabilidade da VCL em tempo de design. Adotar o Assigned como padrão para tudo pode criar uma consistência no código, mas entender por que ele existe separa o programador que apenas escreve código daquele que entende a ferramenta que usa.
Para seus componentes, não arrisque: vá de Assigned.
Fonte de referência: The Oracle at Delphi – Assigned or not Assigned
Descubra mais sobre Régys Borges da Silveira
Assine para receber nossas notícias mais recentes por e-mail.
Ótima explicação Regys, como sempre uma boa didática ajuda bastante a entender um conceito com mais clareza. Eu sempre utilizo o Assigned como padrão exatamente para ter uma consistência no código.