PDA

Ver la Versión Completa : Metodos que devuelven referencias a sí mismos


shaktale
05-06-2003, 18:28:10
Saludos a todos,

Estoy haciendo un cosa un poco rara, se trata más de probar que de que sea realmente util, pero he llegado a un punto en el que no entiendo por qué me está fallando.

La idea es la siguiente:

He definido una clase TTabla, que tiene (entre otros) los siguientes metodos:


function TTabla.AddTitulos(t:array of THTMLDoc):TTabla;
begin
...
Result:=Self;
end;

function TTabla.AddLinea(l:array of THTMLDoc):TTabla;
begin
...
Result:=Self;
end;


La idea de esto es que te devulva una referencia a si mismo para poder aplicar varias veces estos metodos de la siguiente forma:


t:=TTabla.Create.AddTitulos([TLinea.Create('t')]).AddLinea([TLinea.Create('l1')])


el problema está en que sí que puedo aplicar una vez, es decir algo como esto funciona bien:


t:=TTabla.Create.AddTitulos([TLinea.Create('t')]);


pero si le pongo después otro AddLinea me da un error de acceso a la mem.

¿Alguien ha tenido alguna vez un problema similar?

Muchas gracias por vuestro tiempo

delphi.com.ar
05-06-2003, 19:44:16
Sinceramente, creo que lo que vas a lograr es conglomerar el código y va a quedar poco claro.
¿Porqué hacer algo tan feo y puedes escribirlo prolijamente en varias líneas? (Es solo una opinión personal :D )
Yo tengo como norma, escribir el código lo más claro posible, para cualquier programador que retome el sistema pueda entenderlo sin problemas.

Saludos!

roman
05-06-2003, 21:11:14
Esto me recuerda la forma en que se creaban los menús en Turbo Visión. Toda la estructura se declaraba en una solo llamada a procedimiento, algo así como:


CreateMainMenu(
CreateMenu('item', 'item', 'item'),
CreateMenu('item', 'item', 'item'),
CreateMenu('item', 'item',
CreateSubMenu('item', 'item',
CreateSubMenu('item', 'item')
)
),
'item'
)


Si no están bien balanceados mis paréntesis es natural. Eso es lo que pasaba siempre.

// Saludos

gatosoft
06-06-2003, 01:02:12
t:=TTabla.Create.AddTitulos([TLinea.Create('t')]).AddLinea([TLinea.Create('l1')])


La idea es bien interesante... yo creo que el error esta en que la funcion addLinea tiene dentro de si una operacion que realizar... supongo que el compilador intenta realizar las operaciones mas internas primero y despues las mas externas.... (bueno de hecho todos trabajan asi)

Por lo tanto:

TLinea.Create('l1') se ejecuta primero, y luego, intenta pasarla a la funcion AddLinea, que aun no ha sido creada.... y entonces ocurre el "error read address FFFFFFFF" que frecuentemente es el error de que sale cuando no se ha instanciado un objeto.


No estoy seuro, pero el problema debe estar por ahí.


Saludos...

shaktale
06-06-2003, 09:59:58
En primer lugar gracias por las respuestas.

Ya se que no es una manera muy elegante de programar, pero como ya dije lo queria hacer más en plan de prueba que por su utilidad o claridad.

Con respecto a lo que comentas, gatosoft, supongo que andará por ahi el tema, pero entonces lo que no entiendo es por qué SI que funciona lo siguiente:


t:=TTabla.Create.AddTitulos([TLinea.Create('t')]);


saludos

gatosoft
06-06-2003, 16:25:59
Bueno, si trtamos de analizar paso a paso el trabajo del compilador yo diria, sobre esta linea de codigo:


t:=TTabla.Create.AddTitulos([TLinea.Create('t')]).AddLinea([TLinea.Create('ll')])


Primero resuelve los parentesis:

TLinea.Create('t') y TLinea.Create('ll')

Luego, para resolver esta linea, daria prioridad al constructor:

TTabla.Create.AddTitulos(...).AddLinea(...)

pero una vez resuelto eso, el tendria que resolver, si solucionar primero el AddTitulos o el AddLinea:

¿Como sabria el cual tiene prioridad?

Resolver de Izquierda a derecha o de derecha a Izquierda en caso de empate.....

tal vez lo mas obvio , en teoria de objetos (o al menos para mi), seria que resolviera de Derecha a Izquierda....


Objeto.funcion1.funcion2.funcion3
=============>>

Pues el obejto es el que envia los mensajes y es de donde nacen las propedades y los metodos.... En este caso el compilador no tendria problemas... no deberia marcar error en tu codigo

Pero y si intenta resolver la situación en la otra dirección?:

Objeto.funcion1.funcion2.funcion3
<<============

No se por que habria de hacerlo asi.... pero tal parece que asi esta funcionando, o si no...¿de que otra manera podria decir que el objeto no ha sido creado? (creo haber entendido que ese es el error).


Como dices... este ejemplo es mas instructivo que aplicativo.... pues el problema se resuelve partiendo en dos lines tu codigo,pero nos puede ayudar a enteder de alguna forma como trabaja el compilador en estos casos...


suerte.

shaktale
06-06-2003, 16:51:36
Tengo que revisar el código porque parece que el problema no está (sólo) en la llamada en cuestión sino también en qué otros objetos de tipo THTMLDoc hay creados.

Para quien le interese: lo que trataba de hacer es de crear una estructura (THTMLDoc) que representa un fichero HTML, este objeto puede contener a su vez otros objetos de tipo THTMLDoc de forma recursiva y generar así páginas HTML en forma de objtos que se van añadiendo. De hecho me funcionaba bien teniendo los métodos Add como procedures, pero había que probar...

...paranoias que me monto... :p

Gracias otra vez

jachguate
07-06-2003, 03:13:31
que tiempos aquellos de Turbo Vision...

El problema no está en el código que has mostrado en si....

Creo que debes revisar cómo manejas la memoria... pues por allí encontraras seguramente algun bug...

Para ilustrarlo, he hecho este ejemplo, totalmente inutil... pero que compila y funciona perfectamente...

Primero crea un unit, y pegá el siguiente código:



unit Unit2;

interface

Type
TJachElem = Class
private
a : Integer;
b : Integer;
function GetaValue: Integer;
function GetbValue: Integer;
public
Constructor Create(aa, ab: Integer);
Destructor Destroy; override;
Property aValue : Integer read GetaValue;
Property bValue : Integer read GetbValue;
end;

TJachTable = Class
private
Elem1 : TJachElem;
Elem2 : TJachElem;
function GetElem1a: Integer;
function GetElem1b: Integer;
function GetElem2a: Integer;
function GetElem2b: Integer;
public
Constructor Create;
Destructor Destroy; override;
Function AddElem1(aElem : TJachElem) : TJachTable;
Function AddElem2(aElem : TJachElem) : TJachTable;
Property Elem1a : Integer read GetElem1a;
Property Elem1b : Integer read GetElem1b;
Property Elem2a : Integer read GetElem2a;
Property Elem2b : Integer read GetElem2b;
end;

implementation
uses SysUtils;

{ tJachElem }

constructor tJachElem.Create(aa, ab: Integer);
begin
inherited create;
a := aa;
b := ab;
end;

destructor tJachElem.Destroy;
begin

inherited;
end;

function TJachElem.GetaValue: Integer;
begin
Result := a;
end;

function TJachElem.GetbValue: Integer;
begin
Result := b;
end;

{ tJachTable }

function TJachTable.AddElem1(aElem: TJachElem): TJachTable;
begin
if assigned(Elem1) Then
Elem1.Free;
Elem1 := aElem;
Result := Self;
end;

function TJachTable.AddElem2(aElem: TJachElem): TJachTable;
begin
if assigned(Elem2) Then
Elem2.Free;
Elem2 := aElem;
Result := Self;
end;

constructor tJachTable.Create;
begin
inherited;
end;

destructor tJachTable.Destroy;
begin
if Assigned(Elem1) Then
Elem1.Free;
if assigned(Elem2) Then
Elem2.Free;
inherited;
end;

function TJachTable.GetElem1a: Integer;
begin
if not Assigned(Elem1) Then
raise Exception.Create('No se ha asignado Elem1!');
Result := Elem1.aValue;
end;

function TJachTable.GetElem1b: Integer;
begin
if not Assigned(Elem1) Then
raise Exception.Create('No se ha asignado Elem1!');
Result := Elem1.bValue;
end;

function TJachTable.GetElem2a: Integer;
begin
if not Assigned(Elem2) Then
raise Exception.Create('No se ha asignado Elem2!');
Result := Elem2.aValue;
end;

function TJachTable.GetElem2b: Integer;
begin
if not Assigned(Elem2) Then
raise Exception.Create('No se ha asignado Elem2!');
Result := Elem2.bValue;
end;

end.



Luego en otro unit podes hacer esta llamada:


Var
FTabla : TJachTable;

Begin
FTabla := TJachTable.Create.AddElem1(TJachElem.Create(1, 2)).AddElem2(TJachElem.Create(2, 1));
try
Label1.Caption := IntToStr(FTabla.Elem1a);
Label2.Caption := IntToStr(FTabla.Elem1b);
Label3.Caption := IntToStr(FTabla.Elem2a);
Label4.Caption := IntToStr(FTabla.Elem2b);
finally
FTabla.Free;
end;
End;



y todo funciona perfectamente.

Hasta luego.

;)

marto
07-06-2003, 04:04:12
Estoy completamente deacuerdo con jachguate, tienes que estar haciendo algo mal dentro de tu código.
No veo que el order de resolución del compilador tenga que ver con el error, ya que éste se produce en ejecución, por lo tanto el compilador tiene que haber resuleto todo bíen. Lo que no tendría sentido es se ejecutase de "derecha a izquierda".
Conclusión.... lo más probable es que hagas algo mal con tus referencias, o que te olvides de instanciar algo o que algun puntero se te quede mirando a vetetuasaberdonde. de todas maneras, sin ver el código es complicado aventurarse a saber qué es