Reputation: 14001
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
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