@nielsie95;
I have 3 odd requests and it's probably really difficult to implement (especially the 3rd suggestion) but would be pretty neat.. The third one is pretty useless if the 1st and 2nd existed.
1. TypeOf for Lape..
procedure Foo(var X);
begin
end;
There's currently no way to tell what type "X" is :l
If you cast it to a pointer though.. then you can get the "name" of the variable being passed but you still won't know its type:
procedure Foo(var X);
begin
writeln(Pointer(X));
end;
var
I, B: Integer;
begin
Foo(@I); //Prints "I".. not "Integer"
Foo(@B); //Prints "B".. not "Integer"
end.
Would be quite useful if you could get the underlying type..
That brings up the next request..
2. DeclType:
An enhanced version of "type-of". Basically a "cast" to the underlying type for pointers or an instantiation of some type.
var
I: Integer;
B: decltype(I); //"B" would be whatever type "I" is..
begin
end.
One usage would be:
Procedure foo(var X);
I: decltype(X); //instantiate a "typeof(X)"..
begin
end;
or even:
Procedure Foo: GenType; //return "decltype(SomeType)".
begin
Result := SomeType;
end;
Procedure Bar: Pointer;
begin
Result := @ Something;
end;
begin
writeln(Foo.Field_From_SomeType);
writeln(decltype(Bar)^.Field_From_Something);
end;
I guess you could say that it helps for generic types.
With this in mind, that would allow a 3rd type.. "GenType" would be a pointer to a generic type such that when de-referenced, you get the original value back. This would allow non-casting dynamic polymorphism.. It would be far stronger than TVariant.
type Vehicle = record
Name: String;
Wheels: Integer;
Doors: Integer;
Seats: Integer;
end;
type Car = record(Vehicle)
Automatic: Boolean;
MaxSpeed: Integer;
end;
type Truck = record(Vehicle)
OffRoad: Boolean;
FourWheelDrive: Boolean;
MaxSpeed: Integer;
end;
var
V: Vehicle = ['Vehicle', 4, 2, 4];
C: Car = ['Car', 4, 2, 4, true, 700];
T: Truck = ['Truck', 4, 2, 4, true, true, 400];
Arr: Array of ^Vehicle;
begin
Arr := [@V, @C, @T];
writeln(Arr);
end;
currently prints:
"V"::0x62C0230 ({NAME = Vehicle, WHEELS = 4, DOORS = 2, SEATS = 4})
"C"::0x62C02C0 ({NAME = Car, WHEELS = 4, DOORS = 2, SEATS = 4})
"T"::0x62C0380 ({NAME = Truck, WHEELS = 4, DOORS = 2, SEATS = 4})
Since they are just pointers to "Vehicle", it "slices" and only prints as many fields as Vehicle has..
However, with "GenType" you could do:
var
V: Vehicle = ['Vehicle', 4, 2, 4];
C: Car = ['Car', 4, 2, 4, true, 700];
T: Truck = ['Truck', 4, 2, 4, true, true, 400];
Arr: Array of GenType;
begin
Arr := [@V, @C, @T];
writeln(Arr);
end;
And it'd print:
"V"::0x62C0230 ({NAME = Vehicle, WHEELS = 4, DOORS = 2, SEATS = 4})
"C"::0x62C02C0 ({NAME = Car, WHEELS = 4, DOORS = 2, SEATS = 4, AUTOMATIC = True, MAXSPEED = 700})
"T"::0x62C0380 ({NAME = Truck, WHEELS = 4, DOORS = 2, SEATS = 4, OFFROAD = True, FOURWHEELDRIVE = True, MAXSPEED = 400})
So that every field gets printed.. You'd be able to access each field through a dereference like so:
Arr: Array of GenType;
begin
Arr := [@V, @C, @T];
writeln(Arr[1]^.MaxSpeed); //Access MaxSpeed through pointer to Vehicle..
end;
But the dereference might be unnecessary since you can just cast it to the right type and access the fields.. That's only be possible if you knew what type it was though so the first and second requests would have to exist..
The reason these COULD be useful is for a Generic sort.. For example:
type
RSObject = record
ID: Integer;
X, Y: Integer;
end;
type
WallObj = record(RSObject)
Name: String;
end;
type
GroundObj = record(RSObject)
Name: String;
end;
Function TypeOf(Ptr: Pointer): String;
begin
Result := Between('"', '"::', ToStr(Ptr));
end;
Procedure PtrSwap(A, B: Pointer; Size_Ptr: Integer);
type
BytePtr = ^Byte;
var
I: Integer;
T: Byte;
Begin
T := 0;
While (I < Size_Ptr) Do
Begin
T := BytePtr(A[I])^;
BytePtr(A[I])^ := BytePtr(B[I])^;
BytePtr(B[I])^ := T;
Inc(I);
End;
End;
{*
List: Pointer to an array of objects to be sorted.
Size_Ptr: Sizeof(List[X]);
Comparator: Function to compare two elements in the list given a pointer to each.
*}
Procedure GenSort(List: Pointer; Size_Ptr: Integer; Comparator: Function(A, B: Pointer): Boolean);
type
PUInt32 = ^Uint32;
var
Size: Integer;
I, J: Integer;
Begin
I := 0;
Size := ((PUInt32(List) - sizeof(UInt32))^ + 1) * Size_Ptr;
While(I < Size) Do
Begin
J := 0;
While(J < Size - I - Size_Ptr) Do
Begin
If (Comparator(List[J + Size_Ptr], List[J])) Then
PtrSwap(List[J + Size_Ptr], List[J], Size_Ptr);
J := J + Size_Ptr;
End;
I := I + Size_Ptr;
End;
End;
{*
List: Pointer to an array of pointers to objects to be sorted.
Comparator: Function to compare two elements in the list given a pointer a pointer to each.
*}
Procedure GenSort(List: Array of Pointer; Comparator: Function(A, B: Pointer): Boolean); overload;
var
Size: Integer;
Size_Ptr: Integer;
I, J: Integer;
Begin
I := 0;
Size_Ptr := sizeof(Pointer);
Size := Length(List) * Size_Ptr;
While(I < Size) Do
Begin
J := 0;
While(J < Size - I - Size_Ptr) Do
Begin
If (Comparator(List[J + 1], List[J])) Then
Swap(List[J + 1], List[J]);
J := J + Size_Ptr;
End;
I := I + Size_Ptr;
End;
End;
Function CompRSObjectIDs(A, B: Pointer): Boolean;
begin
writeln('Comparing Variable: "', TypeOf(A), '" With Variable: "', TypeOf(B), '"');
Result := RSObject(A^).ID < RSObject(B^).ID;
end;
var
Arr: Array of ^RSObject;
WO: WallObj;
GO: GroundObj;
Arr2: TIntegerArray;
begin
WO := [5, 50, 50, 'Wall-Picture'];
GO := [1, 100, 100, 'Ground-Ashes'];
Arr2 := [9, 10, 3, 4, 1, 2, 8, 7, 6, 5];
SetLength(Arr, 2);
Arr[0] := @WO; //first object is a WallObj
Arr[1] := @GO; //second object is a GroundObj
GenSort(Arr, @CompRSObjectIDs); //Sort polymorphic array by ID's..
//After sorting, the first object is a "GroundObj" and the second is a "WallObj".. You'd have no idea though unless you check with "TypeOf" above to see which variable name is which..
//GenSort(Arr2, sizeof(Integer), @CompInts);
end;
But after sorting, you have no idea which object is which.. You'd have to store a "name" of each variable to figure out what to cast to in order to get it to print the entire object and not just the parent members..