I have simple needs. I have a base class with some generic behavior and subclasses with specific information for that generic behavior. More concretely, the subclasses need to provide the generic behavior with an ordered list of things that designate key fields on database tables. The best representation of those “things” in Delphi seems to be members of an enumeration:
type
TKeyField = (kfFoo, kfBar, kfBaz, kfQuux);
Since I need the list of fields to be ordered, I need them in an array:
type
TKeyFieldArray = array of TKeyField;
The declaration of the base class is pretty simple:
type
TBaseClass = class
protected
function GetKeyFieldList : TKeyFieldArray; virtual; abstract;
public
procedure DoSomethingWithKeyFields;
end;
As is the declaration of the subclass:
type
TSubClass = class(TBaseClass)
protected
function GetKeyFieldList : TKeyFieldArray; override;
end;
So where’s the problem? Where’s the hate? The hate is in the implementation. If Delphi had array literals, this would be easy. Something like:
function TSubClass.GetKeyFieldList : TKeyFieldArray;
begin
Result := [kfBar, kfFoo, kfQuux];
end;
But it doesn’t. It has some special magic for array literals if they’re the parameter to a function, but not anywhere else. It does, however, have a syntax for array constants. Perhaps this will work:
function TSubClass.GetKeyFieldList : TKeyFieldArray;
const
keyFieldList : TKeyFieldArray = (kfBar, kfFoo, kfQuux);
begin
Result := keyFieldList;
end;
But no. That TKeyFieldArray
is a dynamic array; Delphi doesn’t
allocate any space for it, so it can’t be a constant value. You have to
tell Delphi how big each constant array is, even though you’re already
telling it how many elements are in the array. So perhaps this is the
solution:
function TSubClass.GetKeyFieldList : TKeyFieldArray;
const
keyFieldList : array[0..2] of TKeyField = (kfBar, kfFoo, kfQuux);
begin
Result := keyFieldList;
end;
But no. Because of Delphi’s approach to static typing, those are actually different types, and are therefore not assignment-compatible. (See previous hates on this subject.) No, here is the code that Delphi makes me type for what should be a one-line function implementation:
function TSubClass.GetKeyFieldList : TKeyFieldArray;
begin
SetLength(Result, 3);
Result[0] := kfBar;
Result[1] := kfFoo;
Result[2] := kfQuux;
end;
And just earlier this morning I was pleased because I read that Delphi
2007 (to which I’ll soon be upgrading from Delphi 5) has for...in
loops,
so I can finally have foreach
. (Can’t get the generics and anonymous
functions in Delphi 2009, because we need .NET and that’s not yet
available for Delphi 2009.) Oh, Delphi. The one hand giveth, and the
entire rest of the stupid, anemic, pox-ridden language taketh away.