I\'m trying to build an custom comparer which allows the assignment of the comparison function to an internal field. In order to ease the creation of the comparer, I tried t
This is not a full fledged answer, rather notes to David's answer and to the topicstarter's question.
Using answer mode for posting source snippets.
class function TDemo.Construct: TDemo;
begin
Result := TDemo.Create();
Result.FVar := Result.CompareInternal;
end;
class function TDemo.Construct: TDemo;
var
Demo: TDemo;
begin
Demo := TDemo.Create();
Demo.FVar := Demo.CompareInternal;
Result := Demo;
end;
Those both snippets use the same template:
Sure, the p.2 here is just one single line, still
So I think we should assume that p.2 has risk of runtime error, risk of exception thrown. Then it is a textbook memory leak. The local function still holds the memory management responsibilities, since it did not passed the result outside. But it also does not fulfill the required cleanup.
From my perspective the correct pattern - and the one giving one more incentive to using a dedicated local variable than mere Result/Result
compiler confusion - should be
class function TDemo.Construct: TDemo;
var
Demo: TDemo;
begin
Demo := TDemo.Create(); // stage 1: creating an object
try // stage 1: accepting M/M responsibilities
Demo.FVar := Demo.CompareInternal; // stage 2: tuning and facing
// Demo.xxx := yyy; // ...potential risks of exceptions
// Demo.Connect(zzz); etc
Result := Demo; // stage 3: passing the object outside
Demo := nil; // stage 3: abandoning M/M responsibilities
// function exit should follow this line immediately, without other fault-risky statements
finally
Demo.Free; // proceeding with M/M in case of faults in stage 2
end;
end; // stage 3: passing the object outside - immediately after the assignments!
UPD: ventiseis: And as a side node: I would try to instantiate the configurated comparer TDemo only once. The comparison function should be a stateless function
TDemo = class(TComparer)
private
class var FVar: TConstFunc;
// function CompareInternal(const L, R: string): Integer; STATIC; // also possible
class constructor InitComp;
...
end;
// would only be called once, if the class is actually used somewhere in the project
class constructor TDemo.InitComp;
begin
FVar := function(const L, R: string): Integer
begin
Result := StrToInt(R) - StrToInt(L)
end
end;