quinta-feira, 30 de outubro de 2008

Delphi Generics: Diferenças entre compiladores

Tanto o Free Pascal Compiler (FPC) quanto o CodeGear Delphi possuem suporte a generics, as extensões que permitem definir quais tipos de dados serão usados por classes ou funções (por exemplo) no momento de sua declaração. Hoje há uma tendência da adoção de generics em praticamente todas as linguagens OO. C++ tem seus templates desde o ISO C++94, Java adotou generics a partir de sua versão J2SE 5.0 (em 2004), C# a partir da versão 2.0, e agora é a vez do Object Pascal. (Apesar das diferenças de implementação e uso de generics em cada linguagem, o conceito é basicamente o mesmo.)

Pois bem. A comunidade do FPC terminou implementação de generics para sua versão 2.1.2 (em 2007) . Logo depois, a CodeGear anunciou sua intensão de incluir generics na próxima versão de seu compilador, porém com a sintaxe "ligeiramente" diferente.

Agora, com o lançamento do Delphi 2009, a CodeGear confirma a implementação da sintaxe antes exibida, para desespero da comunidade e, principalmente, dos usuários do FPC...

A sintaxe é "quase" a mesma. Mas como o "quase" faz não compilar, há muita gente de cabelo em pé.

The FPC Way...

type
generic MeuVetor< T > = class
private
_vetor: array of T;
_limite: Integer;
_atual: Integer;
public
constructor Create(tamanho: Integer);
function Adicionar(item: T): Boolean;
function Item(posicao: Integer): T;
end;

constructor MeuVetor.Create(tamanho: Integer);
begin
inherited Create();
SetLength( _vetor, tamanho );
_limite := tamanho;
_atual := 0;
end;

function MeuVetor.Adicionar(item: T): Boolean;
begin
if ( _atual < _limite ) then
begin
_vetor[ _atual ] := item;
Inc( _atual );
Result := True;
end
else
Result := False;
end;

function MeuVetor.Item(posicao: Integer): T;
begin
if ( ( posicao >= 0 ) and ( posicao < _limite ) ) then
Result := _vetor[ posicao ]
else
raise Exception.Create( 'Posição fora da faixa.' );
end;


The Delphi 2009 Way...



type
MeuVetor< T > = class
private
_vetor: array of T;
_limite: Integer;
_atual: Integer;
public
constructor Create(tamanho: Integer);
function Adicionar(item: T): Boolean;
function Item(posicao: Integer): T;
end;

constructor MeuVetor< T >.Create(tamanho: Integer);
begin
inherited Create();
SetLength( _vetor, tamanho );
_limite := tamanho;
_atual := 0;
end;

function MeuVetor< T >.Adicionar(item: T): Boolean;
begin
if ( _atual < _limite ) then
begin
_vetor[ _atual ] := item;
Inc( _atual );
Result := True;
end
else
Result := False;
end;

function MeuVetor< T >.Item(posicao: Integer): T;
begin
if ( ( posicao >= 0 ) and ( posicao < _limite ) ) then
Result := _vetor[ posicao ]
else
raise Exception.Create( 'Posição fora da faixa.' );
end;


Notou as diferenças ? Particularmente, eu prefiro sem a palavra generic na frente do nome da classe. Acho desnecessária. Como outras linguagens, também acho que deixar explícito na implementação dos métodos da classe a indicação de que ela recebe um parâmetro deixa o código mais fácil de entender. Na maneira implementada pelo FPC, se você não olhar a declaração, não vai saber que a classe é um generic. Não vai saber que "T" é um tipo que é parametrizado para a classe.



Em os futuros posts provavelmente darei exemplos de classes implementadas com generics em Object Pascal. Nessas usarei a sintaxe do Delphi 2009.



Espero que em breve possa haver um consenso. De imediato, seria bom se o FPC fizesse com que a palavra "generic" e a indicação dos tipos parametrizados na implementação dos métodos fossem opcionais. Poderia resolver temporariamente algum problema de portabilidade.

3 comentários:

Anônimo disse...

Olá Thiago,

Primeiramente parabéns pelas excelentes postagens, encontrei seu blog pesquisando sobre generics no FPC.

Abraços, vou acompanhar suas postagens pelo feedburner,

Silvio Clécio

Thiago Delgado Pinto disse...
Este comentário foi removido pelo autor.
Thiago Delgado Pinto disse...

Obrigado!

Não tenho tido tempo de postar ultimamente, mas vou tentar. Há coisas interessantes que gostaria de compartilhar e discutir.

Abraço,

-T