Skybuck Flying
2011-09-20 12:40:57 UTC
Hello,
This is my first serious consideration of using generics in real code, but
it seems to miss behave a lot, no warnings/errors giving, but it still
crashes like it's the end of the world ! ;) :)
The idea is to design a simply TBoundingBox which has a Min and a Max
property.
This property could either be a 2D or a 3D coordinate type, which for
convenience is a class to solve the "value property problem", and prevent
the need for pointers.
So that Min.X := 100; will automatically lead to a change of X and not a
useless change as described in the previous thread.
This this program also solves as a nice compiler test, currently the
compiler seems pretty shaky/flimsy ! ;)
// *** Begin of Test Program ***
program TestProgram;
{$APPTYPE CONSOLE}
{
Test generics (bug with Destroy? or design problem ? not error messages
giving in Delphi XE)
version 0.01 created on 20 september 2011 by Skybuck Flying
I would like to try and design generic code so a bounding box could
be re-used for 2D or 3D coordinates,
The example below tries to instantiate 3D coordinates, but all kinds
of bad things happen. Current code leads to access violation at .Min access.
If code is moved to seperate units, the .Destroy inside destructor fails.
How to solve the design problem ? And/Or are it delphi bugs ?
}
uses
SysUtils;
// generics interfaces
type
TCoordinate3D<ComponentType> = class
private
protected
mX : ComponentType;
mY : ComponentType;
mZ : ComponentType;
public
constructor Create;
destructor Destroy; override;
property X : ComponentType read mX write mX;
property Y : ComponentType read mY write mY;
property Z : ComponentType read mZ write mZ;
end;
type
TBoundingBox<TCoordinate : class, constructor> = class
private
protected
mMin : TCoordinate;
mMax : TCoordinate;
public
constructor Create;
destructor Destroy; override;
property Min : TCoordinate read mMin write mMin;
property Max : TCoordinate read mMax write mMax;
end;
// generics implementations
constructor TCoordinate3D<ComponentType>.Create;
begin
inherited Create;
end;
destructor TCoordinate3D<ComponentType>.Destroy;
begin
inherited Destroy;
end;
// ---
constructor TBoundingBox<TCoordinate>.Create;
begin
inherited create;
// perhaps problem here ??? no type passed to TCoordinate ?!?
mMin := TCoordinate.Create;
mMax := TCoordinate.Create;
end;
destructor TBoundingBox<TCoordinate>.Destroy;
begin
mMax.Destroy;
mMin.Destroy;
inherited Destroy;
end;
// instantiations
type
TWorldFloat = double;
type
TWorldCoordinate = TCoordinate3D<TWorldFloat>;
type
TWorldBox = TBoundingBox<TWorldCoordinate>;
procedure Main;
var
vWorldBox : TWorldBox;
begin
vWorldBox := TWorldBox.Create;
// access violation.
vWorldBox.Min.X := -1000000;
vWorldBox.Min.Y := -2000000;
vWorldBox.Min.Z := -3000000;
vWorldBox.Max.X := 4000000;
vWorldBox.Max.Y := 5000000;
vWorldBox.Max.Z := 6000000;
writeln( 'vWorldBox.Min.X: ', vWorldBox.Min.X );
writeln( 'vWorldBox.Min.Y: ', vWorldBox.Min.Y );
writeln( 'vWorldBox.Min.Z: ', vWorldBox.Min.Z );
writeln;
writeln( 'vWorldBox.Max.X: ', vWorldBox.Max.X );
writeln( 'vWorldBox.Max.Y: ', vWorldBox.Max.Y );
writeln( 'vWorldBox.Max.Z: ', vWorldBox.Max.Z );
vWorldBox.Free; // crash when put in seperate units.
end;
begin
try
Main;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
ReadLn;
end.
// *** End of Test Program ***
Bye,
Skybuck.
This is my first serious consideration of using generics in real code, but
it seems to miss behave a lot, no warnings/errors giving, but it still
crashes like it's the end of the world ! ;) :)
The idea is to design a simply TBoundingBox which has a Min and a Max
property.
This property could either be a 2D or a 3D coordinate type, which for
convenience is a class to solve the "value property problem", and prevent
the need for pointers.
So that Min.X := 100; will automatically lead to a change of X and not a
useless change as described in the previous thread.
This this program also solves as a nice compiler test, currently the
compiler seems pretty shaky/flimsy ! ;)
// *** Begin of Test Program ***
program TestProgram;
{$APPTYPE CONSOLE}
{
Test generics (bug with Destroy? or design problem ? not error messages
giving in Delphi XE)
version 0.01 created on 20 september 2011 by Skybuck Flying
I would like to try and design generic code so a bounding box could
be re-used for 2D or 3D coordinates,
The example below tries to instantiate 3D coordinates, but all kinds
of bad things happen. Current code leads to access violation at .Min access.
If code is moved to seperate units, the .Destroy inside destructor fails.
How to solve the design problem ? And/Or are it delphi bugs ?
}
uses
SysUtils;
// generics interfaces
type
TCoordinate3D<ComponentType> = class
private
protected
mX : ComponentType;
mY : ComponentType;
mZ : ComponentType;
public
constructor Create;
destructor Destroy; override;
property X : ComponentType read mX write mX;
property Y : ComponentType read mY write mY;
property Z : ComponentType read mZ write mZ;
end;
type
TBoundingBox<TCoordinate : class, constructor> = class
private
protected
mMin : TCoordinate;
mMax : TCoordinate;
public
constructor Create;
destructor Destroy; override;
property Min : TCoordinate read mMin write mMin;
property Max : TCoordinate read mMax write mMax;
end;
// generics implementations
constructor TCoordinate3D<ComponentType>.Create;
begin
inherited Create;
end;
destructor TCoordinate3D<ComponentType>.Destroy;
begin
inherited Destroy;
end;
// ---
constructor TBoundingBox<TCoordinate>.Create;
begin
inherited create;
// perhaps problem here ??? no type passed to TCoordinate ?!?
mMin := TCoordinate.Create;
mMax := TCoordinate.Create;
end;
destructor TBoundingBox<TCoordinate>.Destroy;
begin
mMax.Destroy;
mMin.Destroy;
inherited Destroy;
end;
// instantiations
type
TWorldFloat = double;
type
TWorldCoordinate = TCoordinate3D<TWorldFloat>;
type
TWorldBox = TBoundingBox<TWorldCoordinate>;
procedure Main;
var
vWorldBox : TWorldBox;
begin
vWorldBox := TWorldBox.Create;
// access violation.
vWorldBox.Min.X := -1000000;
vWorldBox.Min.Y := -2000000;
vWorldBox.Min.Z := -3000000;
vWorldBox.Max.X := 4000000;
vWorldBox.Max.Y := 5000000;
vWorldBox.Max.Z := 6000000;
writeln( 'vWorldBox.Min.X: ', vWorldBox.Min.X );
writeln( 'vWorldBox.Min.Y: ', vWorldBox.Min.Y );
writeln( 'vWorldBox.Min.Z: ', vWorldBox.Min.Z );
writeln;
writeln( 'vWorldBox.Max.X: ', vWorldBox.Max.X );
writeln( 'vWorldBox.Max.Y: ', vWorldBox.Max.Y );
writeln( 'vWorldBox.Max.Z: ', vWorldBox.Max.Z );
vWorldBox.Free; // crash when put in seperate units.
end;
begin
try
Main;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
ReadLn;
end.
// *** End of Test Program ***
Bye,
Skybuck.