David Hoyle 68 Posted November 22, 2020 I'm trying to create a rending engine that can use different canvas's where the coordinate system could Integer or Single. This is so that the differences between the output systems can be abstracted at the canvas level. I've tried to used generics (see code below) but it will not compile. I don't know whether I'm trying to be too ambitious or whether I'm missing something. The below code is a test project that shows the issue. Any help would be appreciated. Note: The below code is not intended to run as it's missing some implementations, I'm just looking for it to compile. Program IndirectGenerics; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; Type IPen<T> = Interface Function GetWidth : T; Procedure SetWidth(Const AValue : T); Property Width : T Read GetWidth Write SetWidth; End; ICanvas<T> = Interface Function GetPen : IPen<T>; Property Pen : IPen<T> Read GetPen; End; TConcreteCanvas<T> = Class(TInterfacedObject, ICanvas<T>) Strict Private FPen : IPen<T>; Strict Protected Function GetPen : IPen<T>; Public Constructor Create; End; TConcreteDrawingEngine<T> = Class Strict Private FCanvas : ICanvas<T>; Strict Protected Public Constructor Create(Const Canvas : ICanvas<T>); Procedure DoSomething; End; { TConcreteCanvas<T> } Constructor TConcreteCanvas<T>.Create; Begin // FPen := End; Function TConcreteCanvas<T>.GetPen: IPen<T>; Begin Result := FPen; End; { TConcreteGantt<T> } Constructor TConcreteDrawingEngine<T>.Create(Const Canvas: ICanvas<T>); Begin FCanvas := Canvas; End; Procedure TConcreteDrawingEngine<T>.DoSomething; Begin FCanvas.Pen.Width := 1; // <= Does not compile as it thinks T is not Integer End; Var IntegerCanvas : ICanvas<Integer>; IntegerDrawingEngine : TConcreteDrawingEngine<Integer>; SingleCanvas : ICanvas<Single>; SingleDrawingEngine : TConcreteDrawingEngine<Single>; Begin Try IntegerCanvas := TConcreteCanvas<Integer>.Create; IntegerDrawingEngine := TConcreteDrawingEngine<Integer>.Create(IntegerCanvas); //... SingleCanvas := TConcreteCanvas<Single>.Create; SingleDrawingEngine := TConcreteDrawingEngine<Single>.Create(SingleCanvas); //... Except On E: Exception Do Writeln(E.ClassName, ': ', E.Message); End; End. Share this post Link to post
David Heffernan 2345 Posted November 22, 2020 Generics likely aren't the right solution here. You need templates which don't exist in Delphi. Share this post Link to post
Eugine Savin 4 Posted November 22, 2020 type TNumbers = class public class function One<T>: T; end; { TNumbers } const OneSingle: Single = 1; OneInteger: Integer = 1; class function TNumbers.One<T>: T; type PT = ^T; begin if TypeInfo(T) = TypeInfo(Single) then Result := PT(@OneSingle)^ else if TypeInfo(T) = TypeInfo(Integer) then Result := PT(@OneInteger)^ else raise Exception.Create('Error Message'); end; ... FPen.Width := TNumbers.One<T>; Share this post Link to post
David Heffernan 2345 Posted November 22, 2020 3 minutes ago, Eugine Savin said: class function One<T>: T What about numbers other than 1? Share this post Link to post
Eugine Savin 4 Posted November 22, 2020 class function TNumbers.FromInteger<T>(AValue: Integer): T; type PSingle = ^Single; begin if TypeInfo(T) = TypeInfo(Single) then PSingle(@Result)^ := AValue else if TypeInfo(T) = TypeInfo(Integer) then PInteger(@Result)^ := AValue else raise Exception.Create('Error Message'); end; Share this post Link to post
David Hoyle 68 Posted November 25, 2020 Thank you @David Heffernan and @Eugine Savin. Clearly, I was too ambitious. I tried a few other things with generics and then abandoned them when they didn't work either. I decided to change the underlying coordinate system to Single from Integer and I'm using TPointF and TRectF and the real-time rendering in my application, even with VCL styles, does not seem to have diminished. Still need to test on an old machine with a crappy graphics card but I think this will allow me to do what I want going forwards. Share this post Link to post