Alguém aqui usa Lazarus?

eu disse na maioria das vezes. lembra?

vc está enganado e não conhece a estrutura da VCL/LCL.

veja esse trecho da VCL:

procedure TControl.Notification(AComponent: TComponent; Operation: TOperation); begin inherited Notification(AComponent, Operation); if Operation = opRemove then begin if AComponent = PopupMenu then PopupMenu := nil else if AComponent = Action then Action := nil else if AComponent = FHostDockSite then FHostDockSite := nil; end; end;

vc vai perceber q quem recebe a notificação é o objeto q tem a referencia e não o objeto referenciado.

concordo q 99% dos programadores pascal não sabem disso.

ou seja. se seu objeto ta fazendo referencia a um q foi destruido é pq ele foi mal implementado.

[quote=GilsonNunes]trabalho com Delphi a ums 15 anos.

atualmente estou trabalhando com Lazarus por ser open e multi-plataforma.

tive um rapido contato com ele a ums 5 anos atraz e julguei estar ainda mt “zigoto”.

mas hoje, acho q dizer q o lazarus é inferior a um Delphi3 é não saber o q fala.

pra falar a verdade o lazarus coloca o Delhi2007 pra traz em mts quisitos.

a grande vantagem q acho nele é q ele melhora a acada dia literalmente.

e temos q derrubar alguns MITOS.

executaveis grandes: mentira. (provar?) desmarque a opção “gerar informação de depuração”;
o exe de 13 mb cai pra 1.5 mb;
ah no delphi ele seria 400 kb. (mas com API até no talo);

lento pra compilar; (mentira) desmarque a opção “sempre contruir tudo”;

essa é do pascal;
não permite referencia circular. mentira; (a verdade é q tem gente q não conhece o pascal)

[code]type
ClasseB = class;

ClasseA = class
strict private
B1 : ClasseB;
B2 : ClasseB;
end;

ClasseB = class
strict private
A1, A2, A3 : ClasseA;
end;
[/code]

isso é referencia circular não?[/quote]

Faz muito tempo que não uso o Lazarus, então não posso dizer se ele é melhor que o Delphi 2007, porém como disse antes, a minha experiência inicial não foi nada agradável.

Com relação a referencia circular, você está certo, mas creio que o que ele quis dizer é a referência circular quando as classe estão em Units diferentes, o que não é permitido!

Eu pessoalmente já utilizei o método que você citou para driblar isso mas pessoalmente eu não gosto pois mistura na mesma unit diversas classes diferentes e muitas vezes com responsabilidades diferentes. Nesse sentido a forma utilizada pelo java é melhor, pois permite que as classes sejam separadas.

eu disse na maioria das vezes. lembra?

vc está enganado e não conhece a estrutura da VCL/LCL.

veja esse trecho da VCL:

procedure TControl.Notification(AComponent: TComponent; Operation: TOperation); begin inherited Notification(AComponent, Operation); if Operation = opRemove then begin if AComponent = PopupMenu then PopupMenu := nil else if AComponent = Action then Action := nil else if AComponent = FHostDockSite then FHostDockSite := nil; end; end;

vc vai perceber q quem recebe a notificação é o objeto q tem a referencia e não o objeto referenciado.

concordo q 99% dos programadores pascal não sabem disso.

ou seja. se seu objeto ta fazendo referencia a um q foi destruido é pq ele foi mal implementado.
[/quote]

Realmente eu não conheço a estrutura da LCL Gilosn, mas da VCL, pelo jeito, eu conheço mais que você.

O Evento Notification da classe de TComponent é chamado quando eu Chamo o Método TComponent.InsertComponent ou TComponent.RemoveComponent e não quando um componente é detruido.
Pessoalmente eu não sei qual a sua experiência com objetos, mas pelo sua colocação creio que não seja muito grande.

[code]procedure TComponent.InsertComponent(AComponent: TComponent);
begin
AComponent.ValidateContainer(Self);
if AComponent.FOwner <> nil then
AComponent.FOwner.RemoveComponent(AComponent);
ValidateRename(AComponent, ‘’, AComponent.FName);
Insert(AComponent);
AComponent.SetReference(True);
if csDesigning in ComponentState then
AComponent.SetDesigning(True);
Notification(AComponent, opInsert);
end;

procedure TComponent.RemoveComponent(AComponent: TComponent);
begin
ValidateRename(AComponent, AComponent.FName, ‘’);
Notification(AComponent, opRemove);
AComponent.SetReference(False);
Remove(AComponent);
end;[/code]

da pra ver q vc entende mesmo!!!

é isso q mata o pascal.

veja bem!!

vamos levar a discursão na boa igual ta indo até agora!!! blz?

vc ta confundindo Notification com RemoveComponent

veja esse trecho:

destructor TComponent.Destroy; begin Destroying; if FFreeNotifies <> nil then begin while Assigned(FFreeNotifies) and (FFreeNotifies.Count > 0) do TComponent(FFreeNotifies[FFreeNotifies.Count - 1]).Notification(Self, opRemove); FreeAndNil(FFreeNotifies); end; DestroyComponents; if FOwner <> nil then FOwner.RemoveComponent(Self); inherited Destroy; end;

mais necessariamente essa linha:

nessa linha ai o componente q ta sendo destruido. ta avisando pra todo mundo, q tem uma referencia monitorada (twiter, rsrs) a ele, q ele será destruido.

vc pegou um trecho q usou o Notification e fez a sua tese em cima dele. Mas esse era apenas um exemplo se vc tivesse olhado com mais cuidado teria percebido logo.

techo do help da Embarcadero

[quote]Notification is called automatically when the component specified by AComponent is about to be inserted or removed, as specified by Operation. By default, components pass along the notification to their owned components, if any.
A component can, if needed, act on the notification that a component is being inserted or removed. For example, if a component has object fields or properties that contain references to other components, it can check the notifications of component removals and invalidate those references as needed.[/quote]

então:
não sei sua experiencia com objeto, mas pelo visto a minha é melhor q a sua.

teste isso no delphi/lazaus

[code]unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls, ExtCtrls;

type
TTeste = class (TTimer)
strict private
FBotao : TButton;
procedure SetBotao(const Value: TButton);
protected
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
procedure ExecTimer(Sender : TObject);
public
property Botao : TButton read FBotao write SetBotao;
end;

TForm1 = class(TForm)
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure FormCreate(Sender: TObject);
procedure FormPaint(Sender: TObject);
private
FTeste : TTeste;
procedure BtnClick(Sender: TObject);
procedure BtnMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

{ TTeste }

procedure TTeste.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited;
if (Operation = opRemove) and (AComponent = FBotao) then
begin
FBotao := nil;

if not (csDestroying in ComponentState) then
  ShowMessage('Botão foi removido e eu vi');

end;
end;

procedure TTeste.SetBotao(const Value: TButton);
begin
if FBotao <> Value then
begin
if Assigned(FBotao) then
FBotao.RemoveFreeNotification(Self);

Enabled := False;
FBotao := Value;

if Assigned(FBotao) then
begin
  FBotao.FreeNotification(Self);
  OnTimer := ExecTimer;
  Enabled := True;
end;

end;
end;

procedure TTeste.ExecTimer;
var
I : Integer;
F : TCustomForm;
begin
if Botao = nil then
Exit;

F := GetParentForm(Botao);
if F = nil then
Exit;

if Botao.Tag and 1 = 0 then
begin
if Botao.Left + 10 + Botao.Width > F.ClientWidth then
begin
Botao.Tag := Botao.Tag or 1;
Botao.Left := Botao.Left - 10;
end else
Botao.Left := Botao.Left + 10;
end else
begin
if Botao.Left - 10 < 0 then
begin
Botao.Tag := Botao.Tag and not 1;
Botao.Left := Botao.Left + 10;
end else
Botao.Left := Botao.Left - 10;
end;

if Botao.Tag and 2 = 0 then
begin
if Botao.Top + 10 + Botao.Height > F.ClientHeight then
begin
Botao.Tag := Botao.Tag or 2;
Botao.Top := Botao.Top - 10;
end else
Botao.Top := Botao.Top + 10;
end else
begin
if Botao.Top - 10 < 0 then
begin
Botao.Tag := Botao.Tag and not 2;
Botao.Top := Botao.Top + 10;
end else
Botao.Top := Botao.Top - 10;
end;
end;

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
FTeste := TTeste.Create(Self); //vai ser destruido qdo esse form for destruido e naõ qdo finalizar a app
FTeste.Interval := 300;
end;

procedure TForm1.BtnClick(Sender: TObject);
begin
Sender.Free;
end;

procedure TForm1.BtnMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Button = mbRight then
if Sender is TButton then
FTeste.Botao := TButton(Sender);
end;

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Button = mbRight then
begin
Tag := Tag + 1;
with TButton.Create(Self) do
begin
Parent := Self;
Left := X;
Top := Y;
Caption := IntToStr(Self.Tag);
OnClick := BtnClick;
OnMouseDown := BtnMouseDown;
end;
end;
end;

procedure TForm1.FormPaint(Sender: TObject);
begin
Canvas.TextOut(100, 30, ‘Direito cria botao’);
Canvas.TextOut(100, 60, ‘Direito sobre o botao Liga ele’);
Canvas.TextOut(100, 90, ‘Esquerdo sobre o botao destroi ele’);
end;

end.

[/code]

Cara, agora entendi o que você colocou e realmente você está certo e eu não conhecia a função RemoveFreeNotification, mas vejo que você ainda mas você ainda não entendeu o que eu coloquei, e por isso falei que você não esta acostumado a trabalhar com objetos.

1)Para que isso funcione, todas as suas classes teriam que herdar de TComponent! O que eu faço com classes que não herdam de TComponent?

2)Ok, todas as minhas classes herdam de TComponent. Você ainda tem fazer:

[code]
//Isso
procedure TTeste.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited;
if (Operation = opRemove) and (AComponent = FBotao) then
begin
FBotao := nil;

if not (csDestroying in ComponentState) then  
  ShowMessage('Botão foi removido e eu vi');  

end;
end;

//E isso
procedure TTeste.SetBotao(const Value: TButton);
begin
if FBotao <> Value then
begin
if Assigned(FBotao) then
FBotao.RemoveFreeNotification(Self);

Enabled := False;  
FBotao := Value;  

if Assigned(FBotao) then  
begin  
  FBotao.FreeNotification(Self);  
  OnTimer := ExecTimer;  
  Enabled := True;  
end;  

end;
end;
[/code]Essas operações são obrigatórias para todas as classes a que eu faço referencia. Então é mais fácil implementar a contagem de referencia (como eu já havia falado em outro post) em uma classe e estende-la e simplesmente fazer minhaClasse.AddReferecia. Claro quer isso impõem outros problemas como não usar mais Free e sim outro método, mas ainda é mais simples do que essa solução, alêm do fato de eu não criar um acoplamento desnecessário.

O maior problema ainda continua sendo que eu não posso aplicar essas soluções a qualquer classe independente da facilidade da implementação. Isso faz com que, alem de eu me preocupar em destruir o objeto, tenho que me preocupar com as referencias a ele.

[quote=x@ndy]Cara, agora entendi o que você colocou e realmente você está certo e eu não conhecia a função RemoveFreeNotification, mas vejo que você ainda mas você ainda não entendeu o que eu coloquei, e por isso falei que você não esta acostumado a trabalhar com objetos.

1)Para que isso funcione, todas as suas classes teriam que herdar de TComponent! O que eu faço com classes que não herdam de TComponent?

2)Ok, todas as minhas classes herdam de TComponent. Você ainda tem fazer:

[code]
//Isso
procedure TTeste.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited;
if (Operation = opRemove) and (AComponent = FBotao) then
begin
FBotao := nil;

if not (csDestroying in ComponentState) then  
  ShowMessage('Botão foi removido e eu vi');  

end;
end;

//E isso
procedure TTeste.SetBotao(const Value: TButton);
begin
if FBotao <> Value then
begin
if Assigned(FBotao) then
FBotao.RemoveFreeNotification(Self);

Enabled := False;  
FBotao := Value;  

if Assigned(FBotao) then  
begin  
  FBotao.FreeNotification(Self);  
  OnTimer := ExecTimer;  
  Enabled := True;  
end;  

end;
end;
[/code]Essas operações são obrigatórias para todas as classes a que eu faço referencia. Então é mais fácil implementar a contagem de referencia (como eu já havia falado em outro post) em uma classe e estende-la e simplesmente fazer minhaClasse.AddReferecia. Claro quer isso impõem outros problemas como não usar mais Free e sim outro método, mas ainda é mais simples do que essa solução, alêm do fato de eu não criar um acoplamento desnecessário.

O maior problema ainda continua sendo que eu não posso aplicar essas soluções a qualquer classe independente da facilidade da implementação. Isso faz com que, alem de eu me preocupar em destruir o objeto, tenho que me preocupar com as referencias a ele.

[/quote]

Todas as classes devem herdar TComponent porque esse modelo necessita de um pai. Com o qt é a mesma coisa, você precisa herdar QObject para que se possa mapear todas as referências. Se for comparar com o java, o mesmo funciona dessa maneira já que todas as classes herdam Object implicitamente. O que é importante ressaltar é que java e o famoso coletor de lixo não são nada mais que contadores de referência, e quem entende de desenvolvimento de software sabe como implementar esses modelos.

A linguagem pascal é uma das mais organizadas que eu já usei. O compilador é rigoroso e te obriga a escrever código organizado. Essa é uma grande vantagem em relação as demais.

eu acho q o problema do pascal, do c++, do clipper, do assembly, etc. é q quem faz os comparativos só conhece java e quer q funcione do mesmo jeito.

por exemplo:
vira e mexe e alguem diz: "td q vc cria vc tem q destruir"
o cara faz assim:

F := TFomCheiodeControles.Create(nil);
F.ShowModal;
F.Free;

será q foi criado só um Form ou um punhado de coisas?
ele teve q destruir td?
lembra do Owner? então, ele q resolveu o problema.
precisou do GC? ficou lixo na mem? agora vai no java e deixa um referencia perdida, estatica principalmente (os apps java são cheios disso) .
ai o cara fica descabelando querendo saber pq o GC não ta liberando a mem.

acho GC ruim? lógico q não!!!
mas o desenvolvedor pode deixar td por conta dele? não!!!

o pessoal desce a lenha no c++ e no pascal. mas qdo precisa de velocidade de verdade, logo alguem grita: Usa JNI!!!
lógico q significa, “faz em outra linguagem” mas fazem de conta q não é bem isso!

Eu programo em Delphi há algum tempo. Esse owner é uma forma de delegar a responsabilidade do gerenciamento de memória de um componente para um formulário, ou tem mais casos em que esse Owner pode ser usado?
Obs: Estou gostando muito do desenrolar desse tópico.

não necessariamente um formulario

[quote=GilsonNunes]eu acho q o problema do pascal, do c++, do clipper, do assembly, etc. é q quem faz os comparativos só conhece java e quer q funcione do mesmo jeito.

por exemplo:
vira e mexe e alguem diz: "td q vc cria vc tem q destruir"
o cara faz assim:

F := TFomCheiodeControles.Create(nil);
F.ShowModal;
F.Free;

será q foi criado só um Form ou um punhado de coisas?
ele teve q destruir td?
lembra do Owner? então, ele q resolveu o problema.
precisou do GC? ficou lixo na mem? agora vai no java e deixa um referencia perdida, estatica principalmente (os apps java são cheios disso) .
ai o cara fica descabelando querendo saber pq o GC não ta liberando a mem.

acho GC ruim? lógico q não!!!
mas o desenvolvedor pode deixar td por conta dele? não!!!

o pessoal desce a lenha no c++ e no pascal. mas qdo precisa de velocidade de verdade, logo alguem grita: Usa JNI!!!
lógico q significa, “faz em outra linguagem” mas fazem de conta q não é bem isso!

[/quote]
Gilson, pelo que eu vi aqui ninguém colocou que o java é a melhor coisa do mundo. O que foi feito foi uma critica a uma ferramenta. Até porque não existe melhor linguagem. Eu entendo que as linguagens são como ferramentas e cada um tem o seu lugar. Acho que devemos usar a ferramenta certa para o problema certo. Eu posso programar com OO em Delphi, mas isso vai me dar muito mais trabalho do que em Java. Agora se eu quero fazer uma aplicação que vai fazer uso intensivo da API do Windows, por exemplo, vou fazer em Delphi, com certeza.
Não pode-se dizer que existe melhor linguagem, por que isso é besteira. Cada uma atende bem a uma necessidade, algumas até se igualam.
O que foi feito é uma crítica em relação ao Lazarus, e todas baseadas na experiência dos usuários. O que foi colocado é um problema que existe na utilização de OO no delphi, que, com um pouco de trabalho, pode ser contornado. Problemas existem em qualquer linguagem não só no Delphi.

[quote=juliocbq]
Todas as classes devem herdar TComponent porque esse modelo necessita de um pai. Com o qt é a mesma coisa, você precisa herdar QObject para que se possa mapear todas as referências. Se for comparar com o java, o mesmo funciona dessa maneira já que todas as classes herdam Object implicitamente. O que é importante ressaltar é que java e o famoso coletor de lixo não são nada mais que contadores de referência, e quem entende de desenvolvimento de software sabe como implementar esses modelos.

A linguagem pascal é uma das mais organizadas que eu já usei. O compilador é rigoroso e te obriga a escrever código organizado. Essa é uma grande vantagem em relação as demais.[/quote]

Julio, no delphi todas as classes herdam, se não for especificado outra classe, de TObjetc, similar ao que acontece no Java. Sendo assim, nesse modelo eu não consegueria gerenciar as classes que não herdam de TComponent. Isso funciona bem para gerenciar componentes da VCL, mas seria no mínimo estranho, herdar de TComponent para criar classes que não sejam componentes. A meu ver seria mais simples implementar nessas Classes a contagem de referencia.

[quote=matheuslmota]Eu programo em Delphi há algum tempo. Esse owner é uma forma de delegar a responsabilidade do gerenciamento de memória de um componente para um formulário, ou tem mais casos em que esse Owner pode ser usado?
Obs: Estou gostando muito do desenrolar desse tópico.[/quote]

Tu pode fazer TMeuObjeto.Create(Owner). Assim, quando o componente O Owner for destruido, todos os outros que o tem como pai também serão.
Mas atenção, isso deve ser usado com cuidado. Utilize principalmente com componentes, pois ai existe uma hierarquia. Em um dominio OO isso pode ser mais um problema que uma solução, pois cria uma hierarquia de classes, e você pode não querer isso.

[quote=x@ndy][quote=juliocbq]
Todas as classes devem herdar TComponent porque esse modelo necessita de um pai. Com o qt é a mesma coisa, você precisa herdar QObject para que se possa mapear todas as referências. Se for comparar com o java, o mesmo funciona dessa maneira já que todas as classes herdam Object implicitamente. O que é importante ressaltar é que java e o famoso coletor de lixo não são nada mais que contadores de referência, e quem entende de desenvolvimento de software sabe como implementar esses modelos.

A linguagem pascal é uma das mais organizadas que eu já usei. O compilador é rigoroso e te obriga a escrever código organizado. Essa é uma grande vantagem em relação as demais.[/quote]

Julio, no delphi todas as classes herdam, se não for especificado outra classe, de TObjetc, similar ao que acontece no Java. Sendo assim, nesse modelo eu não consegueria gerenciar as classes que não herdam de TComponent. Isso funciona bem para gerenciar componentes da VCL, mas seria no mínimo estranho, herdar de TComponent para criar classes que não sejam componentes. A meu ver seria mais simples implementar nessas Classes a contagem de referencia.[/quote]

Nem no delphi nem no pascal herdarão TComponent se você não especificar(ou não usar wizard do delphi para gerar classes). O modelo de gerência de memória por contagem de referencia, além de boa pratica de programação é herdar o objeto pai que implementa o “smart pointer”.

/************ Correção *************/

Usando o delphi o correto é herdar todas as classes de TObject(desculpem postar TComponent, acabei me confundindo no calor da conversa), dessa maneira você está assegurando que seu software implementa contagem de referência, e não vai gerar leaks.

Por exemplo, quando você programa em c++(utilizando a propria standard library), o primeiro objeto a se implementar é justamento um coletor de lixo. Se você não faz isso desenvolve software errado(conforme o que li em livros).

Não é regra implementar nenhum modelo, mas saber conceitos de gerenciamento de memória é essencial para escrever o básico com linguagens que expõem apontadores.

Esse livro aqui foi o melhor que já li nesse quesito. É livro pro resto da vida:

Na verdade não! TObject não implementa contagem de referencia, é necessário criar uma classe que herda dela e ai sim implementar a contagem de referência!

É exatamente isso que é necessário fazer no delphi. No blog do João Morais tem um exemplo de implementação em Delphi: http://blog.joaomorais.com.br/2008/09/06/objetos-contagem-ref.html

[quote=juliocbq]
Não é regra implementar nenhum modelo, mas saber conceitos de gerenciamento de memória é essencial para escrever o básico com linguagens que expõem apontadores.

Esse livro aqui foi o melhor que já li nesse quesito. É livro pro resto da vida:

[/quote]
Obrigado pela dica, assim que sobrar tempo vou ver se compro, to atolado de livros para ler e comprar.

[quote=x@ndy][quote=matheuslmota]Eu programo em Delphi há algum tempo. Esse owner é uma forma de delegar a responsabilidade do gerenciamento de memória de um componente para um formulário, ou tem mais casos em que esse Owner pode ser usado?
Obs: Estou gostando muito do desenrolar desse tópico.[/quote]

Tu pode fazer TMeuObjeto.Create(Owner). Assim, quando o componente O Owner for destruido, todos os outros que o tem como pai também serão.
Mas atenção, isso deve ser usado com cuidado. Utilize principalmente com componentes, pois ai existe uma hierarquia. Em um dominio OO isso pode ser mais um problema que uma solução, pois cria uma hierarquia de classes, e você pode não querer isso.[/quote]

De maneira alguma, a idéia é justamente criar a hierarquia.

no caso do Qt se app morrer todos os objetos são coletados.

[code]
#include
#include

      int main(int argv, char **args)
      {
         QApplication app(argv, args);

          QTextEdit textEdit;
         textEdit.show();

         return app.exec();
     }[/code]

Mas QObject é pesada e você não vai herdar “todas” as classes dela. Vai criar uma hierarquia adequada, os objetos mais leves são gerenciados com auto_ptr.

Na verdade não! TObject não implementa contagem de referencia, é necessário criar uma classe que herda dela e ai sim implementar a contagem de referência!

[/quote]

Você tem razão, quem implementa é esse: TInterfacedObject(de acordo com a documentação).

dessa maneira vai criar uma hierarquia consistente.

[quote=juliocbq][quote=x@ndy][quote=matheuslmota]Eu programo em Delphi há algum tempo. Esse owner é uma forma de delegar a responsabilidade do gerenciamento de memória de um componente para um formulário, ou tem mais casos em que esse Owner pode ser usado?
Obs: Estou gostando muito do desenrolar desse tópico.[/quote]

Tu pode fazer TMeuObjeto.Create(Owner). Assim, quando o componente O Owner for destruido, todos os outros que o tem como pai também serão.
Mas atenção, isso deve ser usado com cuidado. Utilize principalmente com componentes, pois ai existe uma hierarquia. Em um dominio OO isso pode ser mais um problema que uma solução, pois cria uma hierarquia de classes, e você pode não querer isso.[/quote]

De maneira alguma, a idéia é justamente criar a hierarquia.

no caso do Qt se app morrer todos os objetos são coletados.

[code]
#include
#include

      int main(int argv, char **args)
      {
         QApplication app(argv, args);

          QTextEdit textEdit;
         textEdit.show();

         return app.exec();
     }[/code]

Mas QObject é pesada e você não vai herdar “todas” as classes dela. Vai criar uma hierarquia adequada, os objetos mais leves são gerenciados com auto_ptr.[/quote]

Não entendi sua colocação? Todos os domínios devem ter uma hierarquia de classes é isso? Se for eu discordo de você, pois determinados domínios não representam hierarquisa de classes, pelo contrário, existe uma colaboração entre elas, mas nunca uma hierarquia. Pense em um sistema comercial, por exemplo, as muitas classes desse domínio não estão em uma hierarquia, ou até estão, mas pertencem a hierarquias distintas. Se eu usar um Owner isso vai me criar um grave problema, pois eu tenho classes distintas com período de vida distintos. Um outro caso são serviços! Nesse caso não posso contar com o fim da aplicação para liberar a memória! Na verdade já tive esse problema em um sistema assim. Muitas classes eram criadas e a sua memória não era devolvida e assim em alguns dias a memória do servidor era esgotada. Por isso que digo que isso deve ser usado com cuidado.

[quote=juliocbq]
Você tem razão, quem implementa é esse: TInterfacedObject(de acordo com a documentação).

dessa maneira vai criar uma hierarquia consistente.[/quote]

Na verdade também não. Você não pode chamar o método Free de uma classe descendente de TInterfacedObject. Se fizer isso vai ser levantada uma exceção!

eu tenho servidores desenvolvidos em pascal e nunca tive problema com memoria não liberada.

qdo falei do Owner não disse q ele era “um”, mt menos disse q era “uma” hierarquia. disse q ele pode ser usado qdo conveniente.
dei o exemplo do formCheioDeControles q vc não tem q destruir cada controle. o Form seria o Owner deles, mas não de td o projeto.

do jeito q alguns falam parece impossível desenvolver sem GC. Realmente é impossível desenvolver se vc trabalhar no pascal como se tivesse trabalhando com java.

negocio é a pratica.

vamos pensar uma situação real q se tornaria mt dificil sem o GC.

os Objetos q precisam de outros pra se fazer algo, basta colocar na lista “para serem avisados”.
não herda de TComponent? o q seria? q tal usar uma cópia então? seria custoso?
q tal um q implementa uma especie de Share?

sobre a tal Hierarquia q seria criado pelo Owner, ou eu não entendi ou é isso?

o q um TDataSet tem a ver com TForm? e no entanto ele pode ser apropriado por ele.

vejo sempre alguem dizer: se vc destruir um Datamodule enquanto um form tiver usando ele?
pq vc iria destruir esse maldito? pra criar “quizumba”?

eu destruo DataModules. mas com certeza não vai ter nem um form usando ele.
como eu sei? pq não tem nenhuma variavel global recebendo a instancia dele pra um programador avacalhar a coisa.

OO no pascal funciona bem. se vc começar bem.

duas regras importantes:
Regra nº 1: Retornar uma nova instancia só se for construtor ou o metodo tiver um nome do tipo Criar, Novo, Etc.;
Regra nº 2: não esqueça a regra nº 1;

um exemplo da violação dessas regras: (quem diria, a VCL?)

forms.pas linha 5570;

function TCustomForm.GetFormImage: TBitmap; .. begin Result := TBitmap.Create; ...

ai um infeliz acha q ta no java e faz assim:

MeuForm.GetFormImage.SaveToFile(xxxx);
ou
Printer.Canvas.Draw(0, 0, MeuForm.GetFormImage);

a instania retornada por TBitmap.Create; ficou sobrando mais q jiló na janta.

como deveria ser então?

assim:

procedure TCustomForm.GetFormImage(Result : TBitmap); .. begin Result.Width := ClientWidth; Result.Height := ClientHeight; Result.Canvas.Brush := Brush; Result.Canvas.FillRect(ClientRect); Result.Canvas.Lock; try if GetWindowLong(Handle, GWL_STYLE) and WS_BORDER <> 0 then Ofs := -1 // Don't draw form border else Ofs := 0; // There is no border PaintTo(Result.Canvas.Handle, Ofs, Ofs); finally Result.Canvas.Unlock; end; ...

pq ai o cara percebia logo q não tava no eclipse.

Gilson, como tu trabalha em teus projetos? Usa interface Inteligente, no modo tradicional do Delphi, usando DBware, Ou cria uma classe para cada entidade nos teus sistemas?
Digo isso, por que vejo que você não tem muita experiência com sistemas totalmente OO. Suas colocações são válidas, mas são colocações de quem nunca enfrentou os problemas trazidos por um sistema totalmente OO com uma dezena, ou até centena de classes. Pelo que vejo você deve fazer o que eu fiz durante muito tempo, você usa objetos em seus projetos mas não desenvolve orientado a objetos.

Como disse antes, existe uma forma de contornar o problema das referencias no delphi, principalmente usando contagem de referencia, mas isso torna o desenvolvimento mais complexo e sujeito a erros, se fazermos através de notificações, isso se torna ainda mais complexo e mais sujeitos a erros ainda. Quando usamos poucas classes em nossos sistemas é fácil controlar isso porém a media que o número de classes cresce isso muda de figura. Esquecer de uma implementar isso em algum lugar gera erros dificeis de localizar.

Outro problema é a abordagem do delphi no uso de interfaces. Qualquer sistema OO faz uso intensivo de interfaces. Agora quem já criou interfaces no Delphi sabe as dificuldades de o faze-lo.

Como disse antes, delphi é muito bom, mas não é a ferramenta ideal para desenvolver um sistema OO, porém é a melhor ferramenta para usar DBware.