Re: D5 - Class\Collection example??



"Maarten Wiltink" <maarten@xxxxxxxxxxxxxxxxxx> schreef in bericht
news:47123117$0$238$e4fe514c@xxxxxxxxxxxxxxxxx
"Tom de Neef" <tdeneef@xxxxxxxx> wrote in message
news:47113ea2$0$232$e4fe514c@xxxxxxxxxxxxxxxxx
[...]
// what to do about the partner of this partner ?
// It should be self, but you cannot call partner.addPartner(self)
// since it will result in an infinite loop !

Allow me to answer that (possibly rhetorical) question.

The trick is to break the endless loop when you recognise that the
situation has stabilised. You set your own Partner, the Partner sets
you as their partner, you set your own partner to them again, except
whenever you're not changing anything thereby, you stop.

Properties let you do this.

type
TPerson = class(TPersistent) { I like being able to Assign }
private
FPartner: TPerson;
protected
procedure SetPartner(const Value: TPerson); virtual;
function DoPartnerChanging(var NewValue: TPerson); virtual;
procedure DoPartnerChanged; virtual;
public
property Partner: TPerson read FPartner write SetPartner;
end;

...

procedure TPerson.SetPartner(const Value: TPerson);
var NewValue: TPerson;
begin
NewValue:=Value;
if (not (Partner=Value)
and DoPartnerChanging(NewValue)
and not (Partner=NewValue)
)
then begin
FPartner:=NewValue;
DoPartnerChanged;
end;
end;

function TPerson.DoPartnerChanging(var NewValue: TPerson): Boolean;
begin
Result:=not Assigned(Partner) or Partner.ConsentsToBreakup;

if (Result
and Assigned(Partner)
and (Partner.Partner=Self)
)
then Partner.Partner:=nil;
end;

procedure TPerson.DoPartnerChanged;
begin
if (Assigned(Partner))
then begin
Partner.Partner:=Self;

if not (Partner.Partner=Self)
then Partner:=nil;
end;
end;

The logic is complicated by the possibility of the prospective partner
refusing to enter into the relationship. Then you have to roll back your
own Partner assignment, and the forwards and backwards pointers are
momentarily inconsistent. This is why the OnChanging event dispatcher
has such an extensive test before breaking up the current relationship.
The third term was an Assertion inside the if statement, but I think it
would have failed if the reversion code in the OnChanged event dispatcher
ever executed.

The social consequences of this code are left as an exercise to the
reader.


Interesting. (By the way: what does ConsentsToBreakup do ?)
But real life is more complex than this. A person can have had more than one
partner. OK you might say: make Fpartner a list of Tperson and check if the
new partner is present in the list of partners. But that too is doomed. One
of my ancestors was married too the same partner twice (with another
marriage in between). That's why the question was indeed rhetorical. Setting
up genealogical relations needs to be done in a different way. But that's
way beyond the OP's question.
Tom



.



Relevant Pages

  • Re: D5 - ClassCollection example??
    ... // since it will result in an infinite loop! ... You set your own Partner, ... TPerson = class ... function DoPartnerChanging(var NewValue: TPerson); virtual; ...
    (comp.lang.pascal.delphi.misc)
  • Re: D5 - ClassCollection example??
    ... TPerson = class ... function DoPartnerChanging(var NewValue: TPerson); virtual; ... property Partner: ...
    (comp.lang.pascal.delphi.misc)