Uli Gerhardt
Uli Gerhardt

Reputation: 14001

Overload for array of enum

I'm trying to make an old API with an untyped parameter typesafe by using overloaded procedures, say

// old, untyped API:
procedure DoItUntyped(var AEle; ASize: Integer);
begin
  Writeln(ASize);
  // Doing the real work (including modifications to AEle, therefore the "var")
end;

// New typed overloads:
procedure DoIt(var AEle: Word); overload;
begin
  DoItUntyped(AEle, SizeOf(AEle));
end;

procedure DoIt(var AEle: Byte); overload;
begin
  DoItUntyped(AEle, SizeOf(AEle));
end;

I can now use this like this:

procedure Test;
var
  w: Word;
  b: Byte;
  e: TTextLineBreakStyle;
begin
  DoIt(w);
  DoIt(b);
  DoIt(Byte(e));
end;

Note, that it even works for enum types (like e) with little effort (one cast) and quite typesafe (e.g. DoIt(Word(e)); doesn't compile).

Now I want to extend this technique to arrays. This is easy for built-in types:

procedure DoIt(var AEle: array of Word); overload;
begin
  DoItUntyped(AEle, SizeOf(AEle));
end;

procedure DoIt(var AEle: array of Byte); overload;
begin
  DoItUntyped(AEle, SizeOf(AEle));
end;

procedure Test;
var
  w3: array[0..3] of Word;
  b3: array[0..3] of Byte;
  w9: array[0..9] of Word;
  b9: array[0..9] of Byte;
begin
  DoIt(w3);
  DoIt(b3);
  DoIt(w9);
  DoIt(b9);
end;

But it gets ugly for arrays of enums. I can introduce helper types:

procedure Test;
type
  TB3 = array[0..3] of Byte;
  TB9 = array[0..9] of Byte;
var
  e3: array[0..3] of TTextLineBreakStyle;
  e9: array[0..9] of TTextLineBreakStyle;
begin
  DoIt(TB3(e3));
  DoIt(TB9(e9));
end;

but I'd need one helper type for every type and array length. An alternative approach might be to add a separate parameter for the array length, but this needs repetitive calls:

procedure DoItArray(var AFirstEle: Word; ALength: Integer); overload;
begin
  DoItUntyped(AFirstEle, SizeOf(AFirstEle) * ALength);
end;

procedure DoItArray(var AFirstEle: Byte; ALength: Integer); overload;
begin
  DoItUntyped(AFirstEle, SizeOf(AFirstEle) * ALength);
end;

procedure Test;
var
  e3: array[0..3] of TTextLineBreakStyle;
  e9: array[0..9] of TTextLineBreakStyle;
begin
  DoItArray(Byte(e3[Low(e3)]), Length(e3));
  DoItArray(Byte(e9[Low(e9)]), Length(e9));
end;

Up to now the best solution seems to add overloads for the (probably many) enum types too:

procedure DoIt(var AEle: TTextLineBreakStyle); overload;
procedure DoIt(var AEle: array of TTextLineBreakStyle); overload;

Before I proceed I'd like to know if anybody has an idea with less repetition. Please note that we still have to use D2007, so no generics.

Upvotes: 1

Views: 194

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 595971

Drop the var specifiers from your overloads, you don't need it unless you want the functions to modify the variables being passed in:

// old, untyped API:
procedure DoItUntyped(var AEle; ASize: Integer);
begin
  Writeln(ASize);
  // Doing the real work
end;

// New typed overloads:
procedure DoIt(AEle: Word); overload;
begin
  DoItUntyped(AEle, SizeOf(AEle));
end;

procedure DoIt(AEle: Byte); overload;
begin
  DoItUntyped(AEle, SizeOf(AEle));
end;

procedure Test;
var
  w: Word;
  b: Byte;
  e: TTextLineBreakStyle;
begin
  DoIt(w);
  DoIt(b);
  DoIt(Byte(e));
end;

Arrays can then be done like this:

procedure DoIt(AEle: array of Word); overload;
begin
  DoItUntyped(PWord(AEle)^, Length(AEle) * SizeOf(Word));
end;

procedure DoIt(AEle: array of Byte); overload;
begin
  DoItUntyped(PByte(AEle)^, Length(AEle) * SizeOf(Byte));
end;

procedure DoIt(AEle: array of TTextLineBreakStyle); overload;
var
  PTextLineBreakStyle = ^TTextLineBreakStyle;
begin
  DoItUntyped(PTextLineBreakStyle(AEle)^, Length(AEle) * SizeOf(TTextLineBreakStyle));
end;

procedure Test;
var
  w3: array[0..3] of Word;
  b3: array[0..3] of Byte;
  w9: array[0..9] of Word;
  b9: array[0..9] of Byte;
  e3: array[0..3] of TTextLineBreakStyle;
  e9: array[0..9] of TTextLineBreakStyle;
begin
  DoIt(w3);
  DoIt(b3);
  DoIt(w9);
  DoIt(b9);
  DoIt(e3);
  DoIt(e9);
end;

Upvotes: 1

Related Questions