SITUATION
I am studying "More Coding in Delphi" by Nick Hodges, and he is using a TFraction record to explain operator overloading. I have written by myself this record:
type
TFraction = record
strict private
aNumerator: integer;
aDenominator: integer;
function GCD(a, b: integer): integer;
public
constructor Create(aNumerator: integer; aDenominator: integer);
procedure Reduce;
class operator Add(fraction1, fraction2: TFraction): TFraction;
class operator Subtract(fraction1, fraction2: TFraction): TFraction;
//... implicit, explicit, multiply...
property Numerator: integer read aNumerator;
property Denominator: integer read aDenominator;
end;
Of course, I had to create a constructor because in Q (rationals) I must have a denominator that is not equal to zero.
constructor TFraction.Create(aNumerator, aDenominator: integer);
begin
if (aDenominator = 0) then
begin
raise Exception.Create('Denominator cannot be zero in rationals!');
end;
if ( (aNumerator < 0) or (aDenominator < 0) ) then
begin
Self.aNumerator := -aNumerator;
Self.aDenominator := -aDenominator;
end
else
begin
Self.aNumerator := aNumerator;
Self.aDenominator := aDenominator;
end;
end;
PROBLEM
Since the operator overloads return a TFraction, I am going to define an operation like this:
class operator TFraction.Add(fraction1, fraction2: TFraction): TFraction;
var
tmp: TFraction;
begin
//simple algorithm of the sum
tmp := TFraction.Create(fraction1.Numerator*fraction2.Denominator+fraction1.Denominator*fraction2.Numerator, fraction1.Denominator*fraction2.Denominator);
tmp.Reduce;
//return the result
Result := tmp;
end;
As you can see here, I am creating a tmp that is returned from the function.
When I read Marco Cantu's book, he used another approach:
class operator TFraction.Add(fraction1, fraction2: TFraction): TFraction;
begin
Result.aNumerator := (fraction1.Numerator*fraction2.Denominator+fraction1.Denominator*fraction2.Numerator);
Result.aDenominator := fraction1.Denominator*fraction2.Denominator;
end;
I have made some tests, and I see that both give me the correct result, but there is something that I cannot understand. In the first approach, I am declaring tmp and then I call the constructor so I can return a TFraction. In the second approach, I am instead not creating anything because records have an automatic constructor. The documentation, in fact, says that:
Records are constructed automatically, using a default no-argument constructor, but classes must be explicitly constructed. Because records have a default no-argument constructor, any user-defined record constructor must have one or more parameters.
Here I have a user-defined record constructor. So:
Is the constructor call on
tmpof the first approach not needed? If I want to callReduce(which is a procedure), I need to create a variable. Is theResultjust returning a copy oftmpwithout creating anything?In the second approach, are
Result.aNumeratorandResult.aDenominatorthe parameters of the automatic created constructor?
Fas the prefix for private fields in a class, and a prefix ofAfor method parameters (which you do use). In Delphi, it's just fine, but apparently, in Lazarus, that would not compile. - Jerry Dodge