Prós e contras do uso da palavra reservada absolute no Delphi

Ícone do Delphi 2010

Algum tempo atrás, analisando uma implementação de código fonte em Delphi, deparei-me com a palavra reservada “absolute” e fiquei bastante intrigado. Afinal, o que era aquela palavra reservada? Para que servia? Quais os prós e contras de sua utilização? Minha primeira reação foi logo a de perguntar para outros programadores Delphi sobre o que seria aquilo, no entanto, para minha surpresa, até mesmo os mais experientes programadores desconheciam do que se tratava aquela palavra. Neste artigo, vou mostrar a utilidade, os benefícios e o perigo do uso desse modificador.

De acordo com os arquivos de ajuda do Delphi, o modificador absolute é uma palavra reservada que torna possível que uma nova variável  resida no mesmo endereço de memória de outra váriavel facilitando type-casting. Por exemplo, no seguinte trecho:

var
  Palavra: string[32];
  TamanhoDaPalavra: Byte absolute Palavra;

Nesse código, dizemos que a variável ‘TamanhoDaPalavra’ deve iniciar no mesmo endereço de memória da variável ‘Palavra’ e, como o primeiro byte de uma string contêm o tamanho dela, temos que a variável ‘TamanhoDaPalavra’ nada mais é do que o próprio tamanho dela!

Essa flexibilidade é por muitas vezes muito útil mas, ao passo em que é interessante, é também insegura, afinal é muito fácil realizar typecasting com ela e, somente os compiladores mais recentes do delphi – por exemplo o delphi 2010 – que alertam, gerando warnings de compilação, sobre  esse perigo.

Apesar disso, na minha opinião, ainda sim pode se tornar uma opção válida quando usada com consciência já que tende a eliminar ruídos de programação gerando um código mais enxuto e para mostrar isso, vou usar o exemplo proposto pelo deltics:

Imaginemos uma situação na qual temos um ComboBox, um Edit e um Memo dentro de um formulário e queremos que tudo o que for escrito neles apareça em caixa-alta. Imaginemos a principio também que, para atender essa funcionalidade, injetamos no evento onChange de cada um desses objetos a seguinte rotina:

procedure TForm1.TornarTextoDoObjetoEmMaiusculas(Sender: TObject);
begin
  if Sender is TEdit then
  begin
    TEdit(Sender).Text := Uppercase(TEdit(Sender).Text);
  end
  else if Sender is TMemo then
  begin
     TMemo(Sender).Text := Uppercase(TMemo(Sender).Text);
  end
  else if (Sender is TComboBox) and (TComboBox(Sender).Style = csDropDown) then
  begin
     TComboBox(Sender).Text := Uppercase(TComboBox(Sender).Text);
  end;
end;

Agora, uma forma para melhorar um pouco essa rotina seria realizar o typecast para variáveis dos próprios objetos utilizados:

procedure TForm1.TornarTextoDoObjetoEmMaiusculas(Sender: TObject);
var
  Edit    : TEdit;
  Memo    : TMemo;
  ComboBox: TComboBox;
begin
  if Sender is TEdit then
  begin
    edit := TEdit(Sender);
    edit.Text := Uppercase(edit.Text);
  end
  else if Sender is TMemo then
  begin
    memo := TMemo(Sender);
    memo.Text := Uppercase(memo.Text);
  end
  else if (Sender is TComboBox) then
  begin
    ComboBox := TComboBox(Sender);
    if (ComboBox.Style = csDropDown) then
    begin
      ComboBox.Text := Uppercase(ComboBox.Text);
    end;
  end;
end;

Agora, vamos introduzir a palavra reservada absolute nessa rotina e observar o resultado:

procedure TForm1.TornarTextoDoObjetoEmMaiusculas(Sender: TObject);
var
  Controle: TObject;
  Edit    : TEdit     absolute Sender;
  Memo    : TMemo     absolute Sender;
  ComboBox: TComboBox absolute Sender;
begin
  Controle := Sender;
  if Sender is TEdit then
  begin
    Edit.Text := Uppercase(Edit.Text);
  end
  else if Sender is TMemo then
  begin
    Memo.Text := Uppercase(Memo.Text);
  end
  else if (Sender is TComboBox) and (ComboBox.Style = csDropDown) then
  begin
    ComboBox.Text := Uppercase(ComboBox.Text);
  end;
end;

Essa última abordagem, é tão segura quanto a anterior no que diz respeito a typecasting a única diferença é agora o casting é realizado na declaração da variável. A introdução da palavra “absolute” simplesmente diz ao compilador para tratar o edit, o memo e o combo como simplesmente diferentes tipos de variáveis alocadas no mesmo endereço de memória da variavel controle, então por que não usar essa capacidade diretamente no parâmetro da procedure Sender?

procedure TForm1.TornarTextoDoObjetoEmMaiusculas(Sender: TObject);
var
  Edit    : TEdit     absolute Sender;
  Memo    : TMemo     absolute Sender;
  ComboBox: TComboBox absolute Sender;
begin
  if (Sender is TEdit) then
  begin
    Edit.Text := UpperCase(Edit.Text);
  end
  else if (Sender is TMemo) then
  begin
    Memo.Text := UpperCase(Memo.Text);
  end
  else if (Sender is TComboBox) and (ComboBox.Style = csDropDown) then
  begin
    ComboBox.Text := UpperCase(ComboBox.Text);
  end;
end;

Ficamos agora com uma rotina mais auto-explicativa, um código mais enxuto, muito mais legível !

Download do código fonte
GIThttps://github.com/fpierin/exemplo_absolute_delphi
SVN: http://fpierin.googlecode.com/svn/trunk/Delphi/keyword_absolute

Referências
http://www.deltics.co.nz/blog/?p=586
http://www.delphigeist.com/2009/09/absolute-directive.html

Anúncios