Open delphidabbler opened 2 years ago
Here's an example function
function Max<T>(const A: array of T; Compare: TComparison<T>): T; overload;
begin
Assert(Length(A) > 0);
Result := A[Low(A)];
for var I := Succ(Low(A)) to High(A) do
begin
if Compare(A[I], Result) > 0 then
Result := A[I];
end;
end;
Here's an example function
function Max<T>(const A: array of T; Compare: TComparison<T>): T; overload; begin Assert(Length(A) > 0); Result := A[Low(A)]; for var I := Succ(Low(A)) to High(A) do begin if Compare(A[I], Result) > 0 then Result := A[I]; end; end;
From what I've read generic global functions can't be declared, so it looks as though the generic functions may need to be grouped together in a static class or record, e.g.:
type
TMinMax = record
class function Max<T>(const A: array of T; Compare: TComparison<T>): T; overload; static;
class function Min<T>(const A: array of T; Compare: TComparison<T>): T; overload; static;
class function Max<T>(const A, B: T; Compare: TComparison<T>): T; overload; static;
class function Min<T>(const A, B: T; Compare: TComparison<T>): T; overload; static;
end;
The reason for putting the type parameter on the metho, rather than the records is so that non-generic methods can be included. For example:
type
TMinMax = record
class function Max<T>(const A: array of T; Compare: TComparison<T>): T; overload; static;
// ...
class function Max(const A: array of Integer): Integer; overload; static;
end;
⚠️ Will need to check if CodeSnip can handle generic routines first.
Can't declare a function or procedure with generic type - instead need to declare a static class or record with generic methods.
Tested a record with generic methods in CodeSnip and it compiled in Delphi 11.
Could generalise this for TArray<T>
by providing a Select
method that is passed a selector closure:
type
TElemSelector = record
public
type
TSelectFn<T> = reference to function(const ACurrent, ACandidate: T; AComparer: IComparer<T>): T;
class function Select<T>(const A: array of T; ASelector: TSelectFn<T>; AComparer: IComparer<T> = nil): T; static;
class function Max<T>(const A: array of T; AComparer: IComparer<T> = nil): T; static;
// ... etc
end;
class function TElemSelector.Select<T>(const A: array of T; ASelector: TSelectFn<T>; AComparer: IComparer<T> = nil): T;
begin
Assert(Length(A) > 0);
if not Assigned(AComparer) then
AComparer := TComparer<T>.Default;
Result := A[Low(A)];
for var I := Succ(Low(A)) to High(A) do
begin
Result := ASelector(Result, A[I], AComparer);
end;
end;
class function TElemSelector.Max<T>(const A: array of T; AComparer: IComparer<T>): T;
begin
Result := Select(
A,
function(const ACurrent, ACandidate: T; AComparer: IComparer<T>): T
begin
if AComparer.Compare(ACurrent, ACandidate) > 0 the
Result := ACurrent
else
Result := ACandidate;
end,
AComparer
);
end
Could generalise this for
TArray<T>
by providing aSelect
method that is passed a selector closure:
Thinking about this further the Select<T>
method doesn't generalise too well, because all the selector fn can do it can do is choose a value based on the comparer, which is pretty much to choose the smallest or greatest, which is what Min & Max do.
Thinking about this further the
Select<T>
method doesn't generalise too well, because all the selector fn can do it can do is choose a value based on the comparer, which is pretty much to choose the smallest or greatest, which is what Min & Max do.
It would be better to create a differently named record with methods that is more generalised that has array operations based on those of JavaScript. E.g.s forEach(), some(), all() & map().
It's difficult to see how to generalise Mid
to an array. What if the array has an even number of elements? Do we average the middle two? If we do and the elements are integral then result may be real.
The easiest way of finding the mid value in an array is to sort the array and pick the middle element if the array length is odd or to average the middle two elements if even. This is the same as taking the median value if the array. This is dealt with in issue #16.
❗ For the above reasons we won't be adding a Mid
function for arrays.
There are lots of overloaded Max, Min and Mid routines in the Maths category of the csdb collection, but it's crying out for some generic versions.
⚠️ Will need to check if CodeSnip can handle generic routines first.